Merge remote-tracking branch 'pleroma/develop' into feature/addressable-lists
authorEgor Kislitsyn <egor@kislitsyn.com>
Tue, 4 Jun 2019 09:28:23 +0000 (16:28 +0700)
committerEgor Kislitsyn <egor@kislitsyn.com>
Tue, 4 Jun 2019 09:28:23 +0000 (16:28 +0700)
1  2 
CHANGELOG.md
docs/api/differences_in_mastoapi_responses.md
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/publisher.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/common_api/common_api.ex
lib/pleroma/web/common_api/utils.ex
lib/pleroma/web/salmon/salmon.ex
test/web/activity_pub/activity_pub_test.exs
test/web/activity_pub/transmogrifier_test.exs

diff --cc CHANGELOG.md
index b8907a23fdd6d37e388b0ae2929121fa2851ca51,8586ea8a0fcf3668cbed0ceb81415f7004c879fd..99b42e280aab3b858ab1cd5868e7175c27e86af2
@@@ -45,7 -49,7 +49,8 @@@ The format is based on [Keep a Changelo
  - OAuth: added job to clean expired access tokens
  - MRF: Support for rejecting reports from specific instances (`mrf_simple`)
  - MRF: Support for stripping avatars and banner images from specific instances (`mrf_simple`)
+ - MRF: Support for running subchains.
 +- Addressable lists
  
  ### Changed
  - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer
index 48aaabe942429a10fbe8dd88ebabb20d87f81e59,45feae25a720fba541480753dd9ef97dd95c7e59..47115aa6e87fc9acafbdc43301ff073b3835c463
@@@ -881,34 -892,23 +889,43 @@@ defmodule Pleroma.Web.ActivityPub.Activ
    end
  
    def fetch_activities(recipients, opts \\ %{}) do
 -    fetch_activities_query(recipients, opts)
 +    list_memberships = Pleroma.List.memberships(opts["user"])
 +
 +    fetch_activities_query(recipients ++ list_memberships, opts)
      |> Pagination.fetch_paginated(opts)
      |> Enum.reverse()
 +    |> maybe_update_cc(list_memberships, opts["user"])
 +  end
 +
 +  defp maybe_update_cc(activities, list_memberships, %User{ap_id: user_ap_id})
 +       when is_list(list_memberships) and length(list_memberships) > 0 do
 +    Enum.map(activities, fn
 +      %{data: %{"bcc" => bcc}} = activity when is_list(bcc) and length(bcc) > 0 ->
 +        if Enum.any?(bcc, &(&1 in list_memberships)) do
 +          update_in(activity.data["cc"], &[user_ap_id | &1])
 +        else
 +          activity
 +        end
 +
 +      activity ->
 +        activity
 +    end)
    end
  
-   def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do
 +  defp maybe_update_cc(activities, _, _), do: activities
 +
+   def fetch_activities_bounded_query(query, recipients, recipients_with_public) do
+     from(activity in query,
+       where:
+         fragment("? && ?", activity.recipients, ^recipients) or
+           (fragment("? && ?", activity.recipients, ^recipients_with_public) and
+              "https://www.w3.org/ns/activitystreams#Public" in activity.recipients)
+     )
+   end
+   def fetch_activities_bounded(recipients, recipients_with_public, opts \\ %{}) do
      fetch_activities_query([], opts)
-     |> restrict_to_cc(recipients_to, recipients_cc)
+     |> fetch_activities_bounded_query(recipients, recipients_with_public)
      |> Pagination.fetch_paginated(opts)
      |> Enum.reverse()
    end
index e8199200eec225ad5f60c624d360094bceccd783,5212d5ce522cae22479ff7d8486d5f4709f66391..85fb32669da676340d2f9f5d69540af6729fe621
@@@ -159,8 -201,8 +206,9 @@@ defmodule Pleroma.Web.CommonAPI d
               data,
               visibility
             ),
+          {poll, poll_emoji} <- make_poll_data(data),
           {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
 +         bcc <- bcc_for_list(user, visibility),
           context <- make_context(in_reply_to),
           cw <- data["spoiler_text"] || "",
           sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}),
             Map.put(
               object,
               "emoji",
-              Formatter.get_emoji_map(full_payload)
+              Map.merge(Formatter.get_emoji_map(full_payload), poll_emoji)
             ) do
 -      res =
 -        ActivityPub.create(
 -          %{
 -            to: to,
 -            actor: user,
 -            context: context,
 -            object: object,
 -            additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
 -          },
 -          Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
 -        )
 -
 -      res
 +      ActivityPub.create(
 +        %{
 +          to: to,
 +          actor: user,
 +          context: context,
 +          object: object,
 +          additional: %{"cc" => cc, "bcc" => bcc, "directMessage" => visibility == "direct"}
 +        },
 +        Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
 +      )
      else
        e -> {:error, e}
      end
index d97a80dd587f22efd79a78d068e24ef74f60f5d8,f35ed36abc55bd7cd14c0ca793cf3ae5716c229c..9c92c6cea88975723ce6d074b3a7c4db9549ff2e
@@@ -102,15 -102,72 +102,81 @@@ defmodule Pleroma.Web.CommonAPI.Utils d
      end
    end
  
 +  def to_for_user_and_mentions(_user, _mentions, _inReplyTo, _), do: {[], []}
 +
 +  def bcc_for_list(user, {:list, list_id}) do
 +    list = Pleroma.List.get(list_id, user)
 +    [list.ap_id]
 +  end
 +
 +  def bcc_for_list(_, _), do: []
 +
+   def make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_in}} = data)
+       when is_list(options) do
+     %{max_expiration: max_expiration, min_expiration: min_expiration} =
+       limits = Pleroma.Config.get([:instance, :poll_limits])
+     # XXX: There is probably a cleaner way of doing this
+     try do
+       # In some cases mastofe sends out strings instead of integers
+       expires_in = if is_binary(expires_in), do: String.to_integer(expires_in), else: expires_in
+       if Enum.count(options) > limits.max_options do
+         raise ArgumentError, message: "Poll can't contain more than #{limits.max_options} options"
+       end
+       {poll, emoji} =
+         Enum.map_reduce(options, %{}, fn option, emoji ->
+           if String.length(option) > limits.max_option_chars do
+             raise ArgumentError,
+               message:
+                 "Poll options cannot be longer than #{limits.max_option_chars} characters each"
+           end
+           {%{
+              "name" => option,
+              "type" => "Note",
+              "replies" => %{"type" => "Collection", "totalItems" => 0}
+            }, Map.merge(emoji, Formatter.get_emoji_map(option))}
+         end)
+       case expires_in do
+         expires_in when expires_in > max_expiration ->
+           raise ArgumentError, message: "Expiration date is too far in the future"
+         expires_in when expires_in < min_expiration ->
+           raise ArgumentError, message: "Expiration date is too soon"
+         _ ->
+           :noop
+       end
+       end_time =
+         NaiveDateTime.utc_now()
+         |> NaiveDateTime.add(expires_in)
+         |> NaiveDateTime.to_iso8601()
+       poll =
+         if Pleroma.Web.ControllerHelper.truthy_param?(data["poll"]["multiple"]) do
+           %{"type" => "Question", "anyOf" => poll, "closed" => end_time}
+         else
+           %{"type" => "Question", "oneOf" => poll, "closed" => end_time}
+         end
+       {poll, emoji}
+     rescue
+       e in ArgumentError -> e.message
+     end
+   end
+   def make_poll_data(%{"poll" => poll}) when is_map(poll) do
+     "Invalid poll"
+   end
+   def make_poll_data(_data) do
+     {%{}, %{}}
+   end
    def make_content_html(
          status,
          attachments,
Simple merge