logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

activity_representer.ex (10984B)


      1 # Pleroma: A lightweight social networking server
      2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
      3 # SPDX-License-Identifier: AGPL-3.0-only
      4 
      5 defmodule Pleroma.Web.OStatus.ActivityRepresenter do
      6   alias Pleroma.Activity
      7   alias Pleroma.Object
      8   alias Pleroma.User
      9   alias Pleroma.Web.OStatus.UserRepresenter
     10 
     11   require Logger
     12   require Pleroma.Constants
     13 
     14   defp get_href(id) do
     15     with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do
     16       external_url
     17     else
     18       _e -> id
     19     end
     20   end
     21 
     22   defp get_in_reply_to(activity) do
     23     with %Object{data: %{"inReplyTo" => in_reply_to}} <- Object.normalize(activity) do
     24       [
     25         {:"thr:in-reply-to",
     26          [ref: to_charlist(in_reply_to), href: to_charlist(get_href(in_reply_to))], []}
     27       ]
     28     else
     29       _ ->
     30         []
     31     end
     32   end
     33 
     34   defp get_mentions(to) do
     35     Enum.map(to, fn id ->
     36       cond do
     37         # Special handling for the AP/Ostatus public collections
     38         Pleroma.Constants.as_public() == id ->
     39           {:link,
     40            [
     41              rel: "mentioned",
     42              "ostatus:object-type": "http://activitystrea.ms/schema/1.0/collection",
     43              href: "http://activityschema.org/collection/public"
     44            ], []}
     45 
     46         # Ostatus doesn't handle follower collections, ignore these.
     47         Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) ->
     48           []
     49 
     50         true ->
     51           {:link,
     52            [
     53              rel: "mentioned",
     54              "ostatus:object-type": "http://activitystrea.ms/schema/1.0/person",
     55              href: id
     56            ], []}
     57       end
     58     end)
     59   end
     60 
     61   defp get_links(%{local: true}, %{"id" => object_id}) do
     62     h = fn str -> [to_charlist(str)] end
     63 
     64     [
     65       {:link, [type: ['application/atom+xml'], href: h.(object_id), rel: 'self'], []},
     66       {:link, [type: ['text/html'], href: h.(object_id), rel: 'alternate'], []}
     67     ]
     68   end
     69 
     70   defp get_links(%{local: false}, %{"external_url" => external_url}) do
     71     h = fn str -> [to_charlist(str)] end
     72 
     73     [
     74       {:link, [type: ['text/html'], href: h.(external_url), rel: 'alternate'], []}
     75     ]
     76   end
     77 
     78   defp get_links(_activity, _object_data), do: []
     79 
     80   defp get_emoji_links(emojis) do
     81     Enum.map(emojis, fn {emoji, file} ->
     82       {:link, [name: to_charlist(emoji), rel: 'emoji', href: to_charlist(file)], []}
     83     end)
     84   end
     85 
     86   def to_simple_form(activity, user, with_author \\ false)
     87 
     88   def to_simple_form(%{data: %{"type" => "Create"}} = activity, user, with_author) do
     89     h = fn str -> [to_charlist(str)] end
     90 
     91     object = Object.normalize(activity)
     92 
     93     updated_at = object.data["published"]
     94     inserted_at = object.data["published"]
     95 
     96     attachments =
     97       Enum.map(object.data["attachment"] || [], fn attachment ->
     98         url = hd(attachment["url"])
     99 
    100         {:link,
    101          [rel: 'enclosure', href: to_charlist(url["href"]), type: to_charlist(url["mediaType"])],
    102          []}
    103       end)
    104 
    105     in_reply_to = get_in_reply_to(activity)
    106     author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
    107     mentions = activity.recipients |> get_mentions
    108 
    109     categories =
    110       (object.data["tag"] || [])
    111       |> Enum.map(fn tag ->
    112         if is_binary(tag) do
    113           {:category, [term: to_charlist(tag)], []}
    114         else
    115           nil
    116         end
    117       end)
    118       |> Enum.filter(& &1)
    119 
    120     emoji_links = get_emoji_links(object.data["emoji"] || %{})
    121 
    122     summary =
    123       if object.data["summary"] do
    124         [{:summary, [], h.(object.data["summary"])}]
    125       else
    126         []
    127       end
    128 
    129     [
    130       {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']},
    131       {:"activity:verb", ['http://activitystrea.ms/schema/1.0/post']},
    132       # For notes, federate the object id.
    133       {:id, h.(object.data["id"])},
    134       {:title, ['New note by #{user.nickname}']},
    135       {:content, [type: 'html'], h.(object.data["content"] |> String.replace(~r/[\n\r]/, ""))},
    136       {:published, h.(inserted_at)},
    137       {:updated, h.(updated_at)},
    138       {:"ostatus:conversation", [ref: h.(activity.data["context"])],
    139        h.(activity.data["context"])},
    140       {:link, [ref: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}
    141     ] ++
    142       summary ++
    143       get_links(activity, object.data) ++
    144       categories ++ attachments ++ in_reply_to ++ author ++ mentions ++ emoji_links
    145   end
    146 
    147   def to_simple_form(%{data: %{"type" => "Like"}} = activity, user, with_author) do
    148     h = fn str -> [to_charlist(str)] end
    149 
    150     updated_at = activity.data["published"]
    151     inserted_at = activity.data["published"]
    152 
    153     author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
    154     mentions = activity.recipients |> get_mentions
    155 
    156     [
    157       {:"activity:verb", ['http://activitystrea.ms/schema/1.0/favorite']},
    158       {:id, h.(activity.data["id"])},
    159       {:title, ['New favorite by #{user.nickname}']},
    160       {:content, [type: 'html'], ['#{user.nickname} favorited something']},
    161       {:published, h.(inserted_at)},
    162       {:updated, h.(updated_at)},
    163       {:"activity:object",
    164        [
    165          {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']},
    166          # For notes, federate the object id.
    167          {:id, h.(activity.data["object"])}
    168        ]},
    169       {:"ostatus:conversation", [ref: h.(activity.data["context"])],
    170        h.(activity.data["context"])},
    171       {:link, [ref: h.(activity.data["context"]), rel: 'ostatus:conversation'], []},
    172       {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []},
    173       {:"thr:in-reply-to", [ref: to_charlist(activity.data["object"])], []}
    174     ] ++ author ++ mentions
    175   end
    176 
    177   def to_simple_form(%{data: %{"type" => "Announce"}} = activity, user, with_author) do
    178     h = fn str -> [to_charlist(str)] end
    179 
    180     updated_at = activity.data["published"]
    181     inserted_at = activity.data["published"]
    182 
    183     author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
    184 
    185     retweeted_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
    186     retweeted_object = Object.normalize(retweeted_activity)
    187     retweeted_user = User.get_cached_by_ap_id(retweeted_activity.data["actor"])
    188 
    189     retweeted_xml = to_simple_form(retweeted_activity, retweeted_user, true)
    190 
    191     mentions =
    192       ([retweeted_user.ap_id] ++ activity.recipients)
    193       |> Enum.uniq()
    194       |> get_mentions()
    195 
    196     [
    197       {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
    198       {:"activity:verb", ['http://activitystrea.ms/schema/1.0/share']},
    199       {:id, h.(activity.data["id"])},
    200       {:title, ['#{user.nickname} repeated a notice']},
    201       {:content, [type: 'html'], ['RT #{retweeted_object.data["content"]}']},
    202       {:published, h.(inserted_at)},
    203       {:updated, h.(updated_at)},
    204       {:"ostatus:conversation", [ref: h.(activity.data["context"])],
    205        h.(activity.data["context"])},
    206       {:link, [ref: h.(activity.data["context"]), rel: 'ostatus:conversation'], []},
    207       {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []},
    208       {:"activity:object", retweeted_xml}
    209     ] ++ mentions ++ author
    210   end
    211 
    212   def to_simple_form(%{data: %{"type" => "Follow"}} = activity, user, with_author) do
    213     h = fn str -> [to_charlist(str)] end
    214 
    215     updated_at = activity.data["published"]
    216     inserted_at = activity.data["published"]
    217 
    218     author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
    219 
    220     mentions = (activity.recipients || []) |> get_mentions
    221 
    222     [
    223       {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
    224       {:"activity:verb", ['http://activitystrea.ms/schema/1.0/follow']},
    225       {:id, h.(activity.data["id"])},
    226       {:title, ['#{user.nickname} started following #{activity.data["object"]}']},
    227       {:content, [type: 'html'],
    228        ['#{user.nickname} started following #{activity.data["object"]}']},
    229       {:published, h.(inserted_at)},
    230       {:updated, h.(updated_at)},
    231       {:"activity:object",
    232        [
    233          {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
    234          {:id, h.(activity.data["object"])},
    235          {:uri, h.(activity.data["object"])}
    236        ]},
    237       {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
    238     ] ++ mentions ++ author
    239   end
    240 
    241   # Only undos of follow for now. Will need to get redone once there are more
    242   def to_simple_form(
    243         %{data: %{"type" => "Undo", "object" => %{"type" => "Follow"} = follow_activity}} =
    244           activity,
    245         user,
    246         with_author
    247       ) do
    248     h = fn str -> [to_charlist(str)] end
    249 
    250     updated_at = activity.data["published"]
    251     inserted_at = activity.data["published"]
    252 
    253     author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
    254 
    255     mentions = (activity.recipients || []) |> get_mentions
    256     follow_activity = Activity.normalize(follow_activity)
    257 
    258     [
    259       {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
    260       {:"activity:verb", ['http://activitystrea.ms/schema/1.0/unfollow']},
    261       {:id, h.(activity.data["id"])},
    262       {:title, ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
    263       {:content, [type: 'html'],
    264        ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
    265       {:published, h.(inserted_at)},
    266       {:updated, h.(updated_at)},
    267       {:"activity:object",
    268        [
    269          {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
    270          {:id, h.(follow_activity.data["object"])},
    271          {:uri, h.(follow_activity.data["object"])}
    272        ]},
    273       {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
    274     ] ++ mentions ++ author
    275   end
    276 
    277   def to_simple_form(%{data: %{"type" => "Delete"}} = activity, user, with_author) do
    278     h = fn str -> [to_charlist(str)] end
    279 
    280     updated_at = activity.data["published"]
    281     inserted_at = activity.data["published"]
    282 
    283     author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
    284 
    285     [
    286       {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
    287       {:"activity:verb", ['http://activitystrea.ms/schema/1.0/delete']},
    288       {:id, h.(activity.data["object"])},
    289       {:title, ['An object was deleted']},
    290       {:content, [type: 'html'], ['An object was deleted']},
    291       {:published, h.(inserted_at)},
    292       {:updated, h.(updated_at)}
    293     ] ++ author
    294   end
    295 
    296   def to_simple_form(_, _, _), do: nil
    297 
    298   def wrap_with_entry(simple_form) do
    299     [
    300       {
    301         :entry,
    302         [
    303           xmlns: 'http://www.w3.org/2005/Atom',
    304           "xmlns:thr": 'http://purl.org/syndication/thread/1.0',
    305           "xmlns:activity": 'http://activitystrea.ms/spec/1.0/',
    306           "xmlns:poco": 'http://portablecontacts.net/spec/1.0',
    307           "xmlns:ostatus": 'http://ostatus.org/schema/1.0'
    308         ],
    309         simple_form
    310       }
    311     ]
    312   end
    313 end