Merge branch 'develop' into feature/polls-2-electric-boogalo
[akkoma] / lib / pleroma / web / activity_pub / utils.ex
index 236d1b4aca4f9c2b9447f68fe2af03867b1c96c1..b292d7d8d57c8de9e2af8c856aab16d34ee0fda1 100644 (file)
@@ -19,7 +19,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
 
   require Logger
 
-  @supported_object_types ["Article", "Note", "Video", "Page"]
+  @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"]
+  @supported_report_states ~w(open closed resolved)
+  @valid_visibilities ~w(public unlisted private direct)
 
   # Some implementations send the actor URI as the actor field, others send the entire actor object,
   # so figure out what the actor's URI is based on what we have.
@@ -670,7 +672,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
       "actor" => params.actor.ap_id,
       "content" => params.content,
       "object" => object,
-      "context" => params.context
+      "context" => params.context,
+      "state" => "open"
     }
     |> Map.merge(additional)
   end
@@ -713,4 +716,94 @@ defmodule Pleroma.Web.ActivityPub.Utils do
       end
     end
   end
+
+  #### Report-related helpers
+
+  def update_report_state(%Activity{} = activity, state) when state in @supported_report_states do
+    with new_data <- Map.put(activity.data, "state", state),
+         changeset <- Changeset.change(activity, data: new_data),
+         {:ok, activity} <- Repo.update(changeset) do
+      {:ok, activity}
+    end
+  end
+
+  def update_report_state(_, _), do: {:error, "Unsupported state"}
+
+  def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do
+    [to, cc, recipients] =
+      activity
+      |> get_updated_targets(visibility)
+      |> Enum.map(&Enum.uniq/1)
+
+    object_data =
+      activity.object.data
+      |> Map.put("to", to)
+      |> Map.put("cc", cc)
+
+    {:ok, object} =
+      activity.object
+      |> Object.change(%{data: object_data})
+      |> Object.update_and_set_cache()
+
+    activity_data =
+      activity.data
+      |> Map.put("to", to)
+      |> Map.put("cc", cc)
+
+    activity
+    |> Map.put(:object, object)
+    |> Activity.change(%{data: activity_data, recipients: recipients})
+    |> Repo.update()
+  end
+
+  def update_activity_visibility(_, _), do: {:error, "Unsupported visibility"}
+
+  defp get_updated_targets(
+         %Activity{data: %{"to" => to} = data, recipients: recipients},
+         visibility
+       ) do
+    cc = Map.get(data, "cc", [])
+    follower_address = User.get_cached_by_ap_id(data["actor"]).follower_address
+    public = "https://www.w3.org/ns/activitystreams#Public"
+
+    case visibility do
+      "public" ->
+        to = [public | List.delete(to, follower_address)]
+        cc = [follower_address | List.delete(cc, public)]
+        recipients = [public | recipients]
+        [to, cc, recipients]
+
+      "private" ->
+        to = [follower_address | List.delete(to, public)]
+        cc = List.delete(cc, public)
+        recipients = List.delete(recipients, public)
+        [to, cc, recipients]
+
+      "unlisted" ->
+        to = [follower_address | List.delete(to, public)]
+        cc = [public | List.delete(cc, follower_address)]
+        recipients = recipients ++ [follower_address, public]
+        [to, cc, recipients]
+
+      _ ->
+        [to, cc, recipients]
+    end
+  end
+
+  def get_existing_votes(actor, %{data: %{"id" => id}}) do
+    query =
+      from(
+        [activity, object: object] in Activity.with_preloaded_object(Activity),
+        where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
+        where:
+          fragment(
+            "(?)->'inReplyTo' = ?",
+            object.data,
+            ^to_string(id)
+          ),
+        where: fragment("(?)->>'type' = 'Answer'", object.data)
+      )
+
+    Repo.all(query)
+  end
 end