Remote interaction with posts (#198)
authorNorm <normandy@biribiri.dev>
Thu, 8 Sep 2022 10:19:22 +0000 (10:19 +0000)
committerfloatingghost <hannah@coffee-and-dreams.uk>
Thu, 8 Sep 2022 10:19:22 +0000 (10:19 +0000)
Grabbed from https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3587

Co-authored-by: Tusooa Zhu <tusooa@kazv.moe>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/198
Co-authored-by: Norm <normandy@biribiri.dev>
Co-committed-by: Norm <normandy@biribiri.dev>
CHANGELOG.md
lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
lib/pleroma/web/mastodon_api/views/instance_view.ex
lib/pleroma/web/router.ex
lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex [new file with mode: 0644]
lib/pleroma/web/twitter_api/controllers/util_controller.ex
lib/pleroma/web/twitter_api/views/util_view.ex
test/pleroma/web/twitter_api/util_controller_test.exs

index e63cc1f6ebe9f7464ac47ef6ffa9b2353eb5d65c..f63fa540c9b55ab07f96ad62368642fdd64aa589 100644 (file)
@@ -42,6 +42,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
   - amd64 is built for debian stable. Compatible with ubuntu 20.
   - ubuntu-jammy is built for... well, ubuntu 22 (LTS)
   - amd64-musl is built for alpine 3.16
+- Enable remote users to interact with posts
 
 ### Fixed
 - Updated mastoFE path, for the newer version
index 4a2a246f5bbfd0e5e223fb17573f702fa15c4e76..c025867a2679bc1ced44616dafcf8a5494c1495b 100644 (file)
@@ -405,6 +405,16 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
     }
   end
 
+  def show_subscribe_form_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Show remote subscribe form",
+      operationId: "UtilController.show_subscribe_form",
+      parameters: [],
+      responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})}
+    }
+  end
+
   defp delete_account_request do
     %Schema{
       title: "AccountDeleteRequest",
index 6612a7ec1fe06f551a6f151a31d6f6d535c017e3..4fed1af74de38453eeb7db3d3b9c3e19e074f043 100644 (file)
@@ -85,7 +85,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
       if Config.get([:translator, :enabled], false) do
         "akkoma:machine_translation"
       end,
-      "custom_emoji_reactions"
+      "custom_emoji_reactions",
+      "pleroma:get:main/ostatus"
     ]
     |> Enum.filter(& &1)
   end
index cc63b2b049d3c31f9162804340fdd95bd3c46c18..f722d94f72ca08d89d9fe81a42a3810d4a20f19e 100644 (file)
@@ -337,6 +337,7 @@ defmodule Pleroma.Web.Router do
     pipe_through(:pleroma_html)
 
     post("/main/ostatus", UtilController, :remote_subscribe)
+    get("/main/ostatus", UtilController, :show_subscribe_form)
     get("/ostatus_subscribe", RemoteFollowController, :follow)
     post("/ostatus_subscribe", RemoteFollowController, :do_follow)
   end
diff --git a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex
new file mode 100644 (file)
index 0000000..d771749
--- /dev/null
@@ -0,0 +1,10 @@
+<%= if @error do %>
+  <h2><%= Gettext.dpgettext("static_pages", "status interact error", "Error: %{error}", error: @error) %></h2>
+<% else %>
+  <h2><%= raw Gettext.dpgettext("static_pages", "status interact header", "Interacting with %{nickname}'s %{status_link}", nickname: safe_to_string(html_escape(@nickname)), status_link: safe_to_string(link(Gettext.dpgettext("static_pages", "status interact header - status link text", "status"), to: @status_link))) %></h2>
+  <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %>
+  <%= hidden_input f, :status_id, value: @status_id %>
+  <%= text_input f, :profile, placeholder: Gettext.dpgettext("static_pages", "placeholder text for account id", "Your account ID, e.g. lain@quitter.se") %>
+  <%= submit Gettext.dpgettext("static_pages", "status interact authorization button", "Interact") %>
+  <% end %>
+<% end %>
index b8abc666e90c6c2149aadf755bbd5a2dba75a776..a0c3e5c52907d50e237e9912d27433088e769f1c 100644 (file)
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
 
   require Logger
 
+  alias Pleroma.Activity
   alias Pleroma.Config
   alias Pleroma.Emoji
   alias Pleroma.Healthcheck
@@ -16,8 +17,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   alias Pleroma.Web.Plugs.OAuthScopesPlug
   alias Pleroma.Web.WebFinger
 
-  plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe)
-  plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe)
+  plug(
+    Pleroma.Web.ApiSpec.CastAndValidate
+    when action != :remote_subscribe and action != :show_subscribe_form
+  )
+
+  plug(
+    Pleroma.Web.Plugs.FederatingPlug
+    when action == :remote_subscribe
+    when action == :show_subscribe_form
+  )
 
   plug(
     OAuthScopesPlug,
@@ -44,7 +53,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
 
   defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation
 
-  def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
+  def show_subscribe_form(conn, %{"nickname" => nick}) do
     with %User{} = user <- User.get_cached_by_nickname(nick),
          avatar = User.avatar_url(user) do
       conn
@@ -54,11 +63,52 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
         render(conn, "subscribe.html", %{
           nickname: nick,
           avatar: nil,
-          error: "Could not find user"
+          error:
+            Pleroma.Web.Gettext.dpgettext(
+              "static_pages",
+              "remote follow error message - user not found",
+              "Could not find user"
+            )
         })
     end
   end
 
+  def show_subscribe_form(conn, %{"status_id" => id}) do
+    with %Activity{} = activity <- Activity.get_by_id(id),
+         {:ok, ap_id} <- get_ap_id(activity),
+         %User{} = user <- User.get_cached_by_ap_id(activity.actor),
+         avatar = User.avatar_url(user) do
+      conn
+      |> render("status_interact.html", %{
+        status_link: ap_id,
+        status_id: id,
+        nickname: user.nickname,
+        avatar: avatar,
+        error: false
+      })
+    else
+      _e ->
+        render(conn, "status_interact.html", %{
+          status_id: id,
+          avatar: nil,
+          error:
+            Pleroma.Web.Gettext.dpgettext(
+              "static_pages",
+              "status interact error message - status not found",
+              "Could not find status"
+            )
+        })
+    end
+  end
+
+  def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
+    show_subscribe_form(conn, %{"nickname" => nick})
+  end
+
+  def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do
+    show_subscribe_form(conn, %{"status_id" => id})
+  end
+
   def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
     with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
          %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
@@ -69,7 +119,33 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
         render(conn, "subscribe.html", %{
           nickname: nick,
           avatar: nil,
-          error: "Something went wrong."
+          error:
+            Pleroma.Web.Gettext.dpgettext(
+              "static_pages",
+              "remote follow error message - unknown error",
+              "Something went wrong."
+            )
+        })
+    end
+  end
+
+  def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profile}}) do
+    with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
+         %Activity{} = activity <- Activity.get_by_id(id),
+         {:ok, ap_id} <- get_ap_id(activity) do
+      conn
+      |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
+    else
+      _e ->
+        render(conn, "status_interact.html", %{
+          status_id: id,
+          avatar: nil,
+          error:
+            Pleroma.Web.Gettext.dpgettext(
+              "static_pages",
+              "status interact error message - unknown error",
+              "Something went wrong."
+            )
         })
     end
   end
@@ -83,6 +159,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     end
   end
 
+  defp get_ap_id(activity) do
+    object = Pleroma.Object.normalize(activity, fetch: false)
+
+    case object do
+      %{data: %{"id" => ap_id}} -> {:ok, ap_id}
+      _ -> {:no_ap_id, nil}
+    end
+  end
+
   def frontend_configurations(conn, _params) do
     render(conn, "frontend_configurations.json")
   end
index a03020290b0129b9f1aa885e1a450284c2c68d2e..6ed74ee80013cdf5d67c968eb5e55a56e0ddd1a5 100644 (file)
@@ -4,7 +4,9 @@
 
 defmodule Pleroma.Web.TwitterAPI.UtilView do
   use Pleroma.Web, :view
+  import Phoenix.HTML
   import Phoenix.HTML.Form
+  import Phoenix.HTML.Link
   alias Pleroma.Config
   alias Pleroma.Web.Endpoint
   alias Pleroma.Web.Gettext
index fb7da93f8fd6c0ab28986c88ee252670e5f7e342..d669cd0fe9663c82269e6b418c51ee3f553c7d04 100644 (file)
@@ -233,6 +233,102 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
     end
   end
 
+  describe "POST /main/ostatus - remote_subscribe/2 - with statuses" do
+    setup do: clear_config([:instance, :federating], true)
+
+    test "renders subscribe form", %{conn: conn} do
+      user = insert(:user)
+      status = insert(:note_activity, %{user: user})
+      status_id = status.id
+
+      assert is_binary(status_id)
+
+      response =
+        conn
+        |> post("/main/ostatus", %{"status_id" => status_id, "profile" => ""})
+        |> response(:ok)
+
+      refute response =~ "Could not find status"
+      assert response =~ "Interacting with"
+    end
+
+    test "renders subscribe form with error when status not found", %{conn: conn} do
+      response =
+        conn
+        |> post("/main/ostatus", %{"status_id" => "somerandomid", "profile" => ""})
+        |> response(:ok)
+
+      assert response =~ "Could not find status"
+      refute response =~ "Interacting with"
+    end
+
+    test "it redirect to webfinger url", %{conn: conn} do
+      user = insert(:user)
+      status = insert(:note_activity, %{user: user})
+      status_id = status.id
+      status_ap_id = status.data["object"]
+
+      assert is_binary(status_id)
+      assert is_binary(status_ap_id)
+
+      user2 = insert(:user, ap_id: "shp@social.heldscal.la")
+
+      conn =
+        conn
+        |> post("/main/ostatus", %{
+          "status" => %{"status_id" => status_id, "profile" => user2.ap_id}
+        })
+
+      assert redirected_to(conn) ==
+               "https://social.heldscal.la/main/ostatussub?profile=#{status_ap_id}"
+    end
+
+    test "it renders form with error when status not found", %{conn: conn} do
+      user2 = insert(:user, ap_id: "shp@social.heldscal.la")
+
+      response =
+        conn
+        |> post("/main/ostatus", %{
+          "status" => %{"status_id" => "somerandomid", "profile" => user2.ap_id}
+        })
+        |> response(:ok)
+
+      assert response =~ "Something went wrong."
+    end
+  end
+
+  describe "GET /main/ostatus - show_subscribe_form/2" do
+    setup do: clear_config([:instance, :federating], true)
+
+    test "it works with users", %{conn: conn} do
+      user = insert(:user)
+
+      response =
+        conn
+        |> get("/main/ostatus", %{"nickname" => user.nickname})
+        |> response(:ok)
+
+      refute response =~ "Could not find user"
+      assert response =~ "Remotely follow #{user.nickname}"
+    end
+
+    test "it works with statuses", %{conn: conn} do
+      user = insert(:user)
+      status = insert(:note_activity, %{user: user})
+      status_id = status.id
+
+      assert is_binary(status_id)
+
+      response =
+        conn
+        |> get("/main/ostatus", %{"status_id" => status_id})
+        |> response(:ok)
+
+      refute response =~ "Could not find status"
+      assert response =~ "Interacting with"
+    end
+  end
+
   test "it returns new captcha", %{conn: conn} do
     with_mock Pleroma.Captcha,
       new: fn -> "test_captcha" end do