Merge branch 'develop' into feature/report-notes
[akkoma] / lib / pleroma / web / admin_api / admin_api_controller.ex
index b6d3f79c8a0145123c28a3c55b3e025f5ea5b548..7c783f91924d87011712413f1c1d0df90df39189 100644 (file)
@@ -7,10 +7,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
   alias Pleroma.Activity
   alias Pleroma.ModerationLog
   alias Pleroma.Plugs.OAuthScopesPlug
+  alias Pleroma.ReportNote
   alias Pleroma.User
   alias Pleroma.UserInviteToken
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Relay
+  alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.AdminAPI.AccountView
   alias Pleroma.Web.AdminAPI.Config
   alias Pleroma.Web.AdminAPI.ConfigView
@@ -29,13 +31,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["read:accounts"]}
+    %{scopes: ["read:accounts"], admin: true}
     when action in [:list_users, :user_show, :right_get, :invites]
   )
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["write:accounts"]}
+    %{scopes: ["write:accounts"], admin: true}
     when action in [
            :get_invite_token,
            :revoke_invite,
@@ -51,42 +53,43 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
            :tag_users,
            :untag_users,
            :right_add,
-           :right_delete,
-           :set_activation_status
+           :right_delete
          ]
   )
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["read:reports"]} when action in [:list_reports, :report_show]
+    %{scopes: ["read:reports"], admin: true}
+    when action in [:list_reports, :report_show]
   )
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["write:reports"]}
+    %{scopes: ["write:reports"], admin: true}
     when action in [:report_update_state, :report_respond]
   )
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["read:statuses"]} when action == :list_user_statuses
+    %{scopes: ["read:statuses"], admin: true}
+    when action == :list_user_statuses
   )
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["write:statuses"]}
+    %{scopes: ["write:statuses"], admin: true}
     when action in [:status_update, :status_delete]
   )
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["read"]}
+    %{scopes: ["read"], admin: true}
     when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log]
   )
 
   plug(
     OAuthScopesPlug,
-    %{scopes: ["write"]}
+    %{scopes: ["write"], admin: true}
     when action in [:relay_follow, :relay_unfollow, :config_update]
   )
 
@@ -227,6 +230,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     end
   end
 
+  def list_instance_statuses(conn, %{"instance" => instance} = params) do
+    {page, page_size} = page_params(params)
+
+    activities =
+      ActivityPub.fetch_instance_activities(%{
+        "instance" => instance,
+        "limit" => page_size,
+        "offset" => (page - 1) * page_size
+      })
+
+    conn
+    |> put_view(StatusView)
+    |> render("index.json", %{activities: activities, as: :activity})
+  end
+
   def list_user_statuses(conn, %{"nickname" => nickname} = params) do
     godmode = params["godmode"] == "true" || params["godmode"] == true
 
@@ -250,9 +268,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
   def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
     user = User.get_cached_by_nickname(nickname)
 
-    {:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
+    {:ok, updated_user} = User.deactivate(user, !user.deactivated)
 
-    action = if user.info.deactivated, do: "activate", else: "deactivate"
+    action = if user.deactivated, do: "activate", else: "deactivate"
 
     ModerationLog.insert_log(%{
       actor: admin,
@@ -335,6 +353,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     }
 
     with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
+         {:ok, users, count} <- filter_service_users(users, count),
          do:
            conn
            |> json(
@@ -346,6 +365,18 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
            )
   end
 
+  defp filter_service_users(users, count) do
+    filtered_users = Enum.reject(users, &service_user?/1)
+    count = if Enum.any?(users, &service_user?/1), do: length(filtered_users), else: count
+
+    {:ok, filtered_users, count}
+  end
+
+  defp service_user?(user) do
+    String.match?(user.ap_id, ~r/.*\/relay$/) or
+      String.match?(user.ap_id, ~r/.*\/internal\/fetch$/)
+  end
+
   @filters ~w(local external active deactivated is_admin is_moderator)
 
   @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
@@ -364,11 +395,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
         "nicknames" => nicknames
       })
       when permission_group in ["moderator", "admin"] do
-    info = Map.put(%{}, "is_" <> permission_group, true)
+    update = %{:"is_#{permission_group}" => true}
 
     users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
 
-    User.update_info(users, &User.Info.admin_api_update(&1, info))
+    for u <- users, do: User.admin_api_update(u, update)
 
     ModerationLog.insert_log(%{
       action: "grant",
@@ -377,7 +408,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
       permission: permission_group
     })
 
-    json(conn, info)
+    json(conn, update)
   end
 
   def right_add_multiple(conn, _) do
@@ -389,12 +420,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
         "nickname" => nickname
       })
       when permission_group in ["moderator", "admin"] do
-    info = Map.put(%{}, "is_" <> permission_group, true)
+    fields = %{:"is_#{permission_group}" => true}
 
     {:ok, user} =
       nickname
       |> User.get_cached_by_nickname()
-      |> User.update_info(&User.Info.admin_api_update(&1, info))
+      |> User.admin_api_update(fields)
 
     ModerationLog.insert_log(%{
       action: "grant",
@@ -403,7 +434,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
       permission: permission_group
     })
 
-    json(conn, info)
+    json(conn, fields)
   end
 
   def right_add(conn, _) do
@@ -415,8 +446,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
 
     conn
     |> json(%{
-      is_moderator: user.info.is_moderator,
-      is_admin: user.info.is_admin
+      is_moderator: user.is_moderator,
+      is_admin: user.is_admin
     })
   end
 
@@ -429,11 +460,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
       )
       when permission_group in ["moderator", "admin"] do
     with false <- Enum.member?(nicknames, admin_nickname) do
-      info = Map.put(%{}, "is_" <> permission_group, false)
+      update = %{:"is_#{permission_group}" => false}
 
       users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
 
-      User.update_info(users, &User.Info.admin_api_update(&1, info))
+      for u <- users, do: User.admin_api_update(u, update)
 
       ModerationLog.insert_log(%{
         action: "revoke",
@@ -442,7 +473,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
         permission: permission_group
       })
 
-      json(conn, info)
+      json(conn, update)
     else
       _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.")
     end
@@ -460,12 +491,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
         }
       )
       when permission_group in ["moderator", "admin"] do
-    info = Map.put(%{}, "is_" <> permission_group, false)
+    fields = %{:"is_#{permission_group}" => false}
 
     {:ok, user} =
       nickname
       |> User.get_cached_by_nickname()
-      |> User.update_info(&User.Info.admin_api_update(&1, info))
+      |> User.admin_api_update(fields)
 
     ModerationLog.insert_log(%{
       action: "revoke",
@@ -474,7 +505,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
       permission: permission_group
     })
 
-    json(conn, info)
+    json(conn, fields)
   end
 
   def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
@@ -596,10 +627,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
   end
 
   @doc "Force password reset for a given user"
-  def force_password_reset(conn, %{"nickname" => nickname}) do
-    (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
+  def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
+    users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
+
+    Enum.map(users, &User.force_password_reset_async/1)
 
-    User.force_password_reset_async(user)
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "force_password_reset"
+    })
 
     json_response(conn, :no_content, "")
   end
@@ -607,21 +644,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
   def list_reports(conn, params) do
     {page, page_size} = page_params(params)
 
-    params =
-      params
-      |> Map.put("type", "Flag")
-      |> Map.put("skip_preload", true)
-      |> Map.put("total", true)
-      |> Map.put("limit", page_size)
-      |> Map.put("offset", (page - 1) * page_size)
-
-    reports = ActivityPub.fetch_activities([], params, :offset)
+    reports = Utils.get_reports(params, page, page_size)
 
     conn
     |> put_view(ReportView)
     |> render("index.json", %{reports: reports})
   end
 
+  def list_grouped_reports(conn, _params) do
+    statuses = Utils.get_reported_activities()
+
+    conn
+    |> put_view(ReportView)
+    |> render("index_grouped.json", Utils.get_reports_grouped_by_status(statuses))
+  end
+
   def report_show(conn, %{"id" => id}) do
     with %Activity{} = report <- Activity.get_by_id(id) do
       conn
@@ -632,46 +669,62 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     end
   end
 
-  def report_update_state(%{assigns: %{user: admin}} = conn, %{"id" => id, "state" => state}) do
-    with {:ok, report} <- CommonAPI.update_report_state(id, state) do
-      ModerationLog.insert_log(%{
-        action: "report_update",
-        actor: admin,
-        subject: report
-      })
+  def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
+    result =
+      reports
+      |> Enum.map(fn report ->
+        with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
+          ModerationLog.insert_log(%{
+            action: "report_update",
+            actor: admin,
+            subject: activity
+          })
+
+          activity
+        else
+          {:error, message} -> %{id: report["id"], error: message}
+        end
+      end)
 
-      conn
-      |> put_view(ReportView)
-      |> render("show.json", Report.extract_report_info(report))
+    case Enum.any?(result, &Map.has_key?(&1, :error)) do
+      true -> json_response(conn, :bad_request, result)
+      false -> json_response(conn, :no_content, "")
     end
   end
 
-  def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
-    with false <- is_nil(params["status"]),
-         %Activity{} <- Activity.get_by_id(id) do
-      params =
-        params
-        |> Map.put("in_reply_to_status_id", id)
-        |> Map.put("visibility", "direct")
+  def report_notes_create(%{assigns: %{user: user}} = conn, %{
+        "id" => report_id,
+        "content" => content
+      }) do
+    with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
+      ModerationLog.insert_log(%{
+        action: "report_note",
+        actor: user,
+        subject: Activity.get_by_id(report_id),
+        text: content
+      })
 
-      {:ok, activity} = CommonAPI.post(user, params)
+      json_response(conn, :no_content, "")
+    else
+      _ -> json_response(conn, :bad_request, "")
+    end
+  end
 
+  def report_notes_delete(%{assigns: %{user: user}} = conn, %{
+        "id" => note_id,
+        "report_id" => report_id
+      }) do
+    with {:ok, note} <- ReportNote.destroy(note_id) do
       ModerationLog.insert_log(%{
-        action: "report_response",
+        action: "report_note_delete",
         actor: user,
-        subject: activity,
-        text: params["status"]
+        subject: Activity.get_by_id(report_id),
+        text: note.content
       })
 
-      conn
-      |> put_view(StatusView)
-      |> render("show.json", %{activity: activity})
+      json_response(conn, :no_content, "")
     else
-      true ->
-        {:param_cast, nil}
-
-      nil ->
-        {:error, :not_found}
+      _ -> json_response(conn, :bad_request, "")
     end
   end
 
@@ -774,6 +827,34 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     conn |> json("ok")
   end
 
+  def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
+    users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
+
+    User.toggle_confirmation(users)
+
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "confirm_email"
+    })
+
+    conn |> json("")
+  end
+
+  def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
+    users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
+
+    User.try_send_confirmation_email(users)
+
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "resend_confirmation_email"
+    })
+
+    conn |> json("")
+  end
+
   def errors(conn, {:error, :not_found}) do
     conn
     |> put_status(:not_found)