aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex26
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex73
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex235
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex46
-rw-r--r--lib/pleroma/web/admin_api/views/report_view.ex20
-rw-r--r--lib/pleroma/web/common_api/common_api.ex26
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex46
-rw-r--r--lib/pleroma/web/router.ex11
-rw-r--r--lib/pleroma/web/static_fe/static_fe_controller.ex51
9 files changed, 488 insertions, 46 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 65dd251f3..d0c014e9d 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -322,6 +322,32 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ def react_with_emoji(user, object, emoji, options \\ []) do
+ with local <- Keyword.get(options, :local, true),
+ activity_id <- Keyword.get(options, :activity_id, nil),
+ Pleroma.Emoji.is_unicode_emoji?(emoji),
+ reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id),
+ {:ok, activity} <- insert(reaction_data, local),
+ {:ok, object} <- add_emoji_reaction_to_object(activity, object),
+ :ok <- maybe_federate(activity) do
+ {:ok, activity, object}
+ end
+ end
+
+ def unreact_with_emoji(user, reaction_id, options \\ []) do
+ with local <- Keyword.get(options, :local, true),
+ activity_id <- Keyword.get(options, :activity_id, nil),
+ user_ap_id <- user.ap_id,
+ %Activity{actor: ^user_ap_id} = reaction_activity <- Activity.get_by_ap_id(reaction_id),
+ object <- Object.normalize(reaction_activity),
+ unreact_data <- make_undo_data(user, reaction_activity, activity_id),
+ {:ok, activity} <- insert(unreact_data, local),
+ {:ok, object} <- remove_emoji_reaction_from_object(reaction_activity, object),
+ :ok <- maybe_federate(activity) do
+ {:ok, activity, object}
+ end
+ end
+
# TODO: This is weird, maybe we shouldn't check here if we can make the activity.
def like(
%User{ap_id: ap_id} = user,
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 91a164eff..15612545b 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -566,6 +566,34 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
+ @misskey_reactions %{
+ "like" => "👍",
+ "love" => "❤️",
+ "laugh" => "😆",
+ "hmm" => "🤔",
+ "surprise" => "😮",
+ "congrats" => "🎉",
+ "angry" => "💢",
+ "confused" => "😥",
+ "rip" => "😇",
+ "pudding" => "🍮",
+ "star" => "⭐"
+ }
+
+ @doc "Rewrite misskey likes into EmojiReactions"
+ def handle_incoming(
+ %{
+ "type" => "Like",
+ "_misskey_reaction" => reaction
+ } = data,
+ options
+ ) do
+ data
+ |> Map.put("type", "EmojiReaction")
+ |> Map.put("content", @misskey_reactions[reaction] || reaction)
+ |> handle_incoming(options)
+ end
+
def handle_incoming(
%{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data,
_options
@@ -581,6 +609,27 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def handle_incoming(
+ %{
+ "type" => "EmojiReaction",
+ "object" => object_id,
+ "actor" => _actor,
+ "id" => id,
+ "content" => emoji
+ } = data,
+ _options
+ ) do
+ with actor <- Containment.get_actor(data),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, object} <- get_obj_helper(object_id),
+ {:ok, activity, _object} <-
+ ActivityPub.react_with_emoji(actor, object, emoji, activity_id: id, local: false) do
+ {:ok, activity}
+ else
+ _e -> :error
+ end
+ end
+
+ def handle_incoming(
%{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data,
_options
) do
@@ -718,6 +767,28 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def handle_incoming(
%{
"type" => "Undo",
+ "object" => %{"type" => "EmojiReaction", "id" => reaction_activity_id},
+ "actor" => _actor,
+ "id" => id
+ } = data,
+ _options
+ ) do
+ with actor <- Containment.get_actor(data),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, activity, _} <-
+ ActivityPub.unreact_with_emoji(actor, reaction_activity_id,
+ activity_id: id,
+ local: false
+ ) do
+ {:ok, activity}
+ else
+ _e -> :error
+ end
+ end
+
+ def handle_incoming(
+ %{
+ "type" => "Undo",
"object" => %{"type" => "Block", "object" => blocked},
"actor" => blocker,
"id" => id
@@ -1048,7 +1119,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
Map.put(object, "attachment", attachments)
end
- defp strip_internal_fields(object) do
+ def strip_internal_fields(object) do
object
|> Map.drop(Pleroma.Constants.object_internal_fields())
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index d812fd734..c45662359 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.Endpoint
@@ -255,6 +256,16 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> Repo.one()
end
+ @doc """
+ Returns like activities targeting an object
+ """
+ def get_object_likes(%{data: %{"id" => id}}) do
+ id
+ |> Activity.Queries.by_object_id()
+ |> Activity.Queries.by_type("Like")
+ |> Repo.all()
+ end
+
@spec make_like_data(User.t(), map(), String.t()) :: map()
def make_like_data(
%User{ap_id: ap_id} = actor,
@@ -286,13 +297,30 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> maybe_put("id", activity_id)
end
+ def make_emoji_reaction_data(user, object, emoji, activity_id) do
+ make_like_data(user, object, activity_id)
+ |> Map.put("type", "EmojiReaction")
+ |> Map.put("content", emoji)
+ end
+
@spec update_element_in_object(String.t(), list(any), Object.t()) ::
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def update_element_in_object(property, element, object) do
+ length =
+ if is_map(element) do
+ element
+ |> Map.values()
+ |> List.flatten()
+ |> length()
+ else
+ element
+ |> length()
+ end
+
data =
Map.merge(
object.data,
- %{"#{property}_count" => length(element), "#{property}s" => element}
+ %{"#{property}_count" => length, "#{property}s" => element}
)
object
@@ -300,6 +328,38 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> Object.update_and_set_cache()
end
+ @spec add_emoji_reaction_to_object(Activity.t(), Object.t()) ::
+ {:ok, Object.t()} | {:error, Ecto.Changeset.t()}
+
+ def add_emoji_reaction_to_object(
+ %Activity{data: %{"content" => emoji, "actor" => actor}},
+ object
+ ) do
+ reactions = object.data["reactions"] || %{}
+ emoji_actors = reactions[emoji] || []
+ new_emoji_actors = [actor | emoji_actors] |> Enum.uniq()
+ new_reactions = Map.put(reactions, emoji, new_emoji_actors)
+ update_element_in_object("reaction", new_reactions, object)
+ end
+
+ def remove_emoji_reaction_from_object(
+ %Activity{data: %{"content" => emoji, "actor" => actor}},
+ object
+ ) do
+ reactions = object.data["reactions"] || %{}
+ emoji_actors = reactions[emoji] || []
+ new_emoji_actors = List.delete(emoji_actors, actor)
+
+ new_reactions =
+ if new_emoji_actors == [] do
+ Map.delete(reactions, emoji)
+ else
+ Map.put(reactions, emoji, new_emoji_actors)
+ end
+
+ update_element_in_object("reaction", new_reactions, object)
+ end
+
@spec add_like_to_object(Activity.t(), Object.t()) ::
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do
@@ -397,6 +457,19 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> Repo.one()
end
+ def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do
+ %{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
+
+ "EmojiReaction"
+ |> Activity.Queries.by_type()
+ |> where(actor: ^ap_id)
+ |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ |> Activity.Queries.by_object_id(object_ap_id)
+ |> order_by([activity], fragment("? desc nulls last", activity.id))
+ |> limit(1)
+ |> Repo.one()
+ end
+
#### Announce-related helpers
@doc """
@@ -489,6 +562,25 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> maybe_put("id", activity_id)
end
+ def make_undo_data(
+ %User{ap_id: actor, follower_address: follower_address},
+ %Activity{
+ data: %{"id" => undone_activity_id, "context" => context},
+ actor: undone_activity_actor
+ },
+ activity_id \\ nil
+ ) do
+ %{
+ "type" => "Undo",
+ "actor" => actor,
+ "object" => undone_activity_id,
+ "to" => [follower_address, undone_activity_actor],
+ "cc" => [Pleroma.Constants.as_public()],
+ "context" => context
+ }
+ |> maybe_put("id", activity_id)
+ end
+
@spec add_announce_to_object(Activity.t(), Object.t()) ::
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def add_announce_to_object(
@@ -615,26 +707,31 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def make_flag_data(_, _), do: %{}
defp build_flag_object(%{account: account, statuses: statuses} = _) do
- [account.ap_id] ++
- Enum.map(statuses || [], fn act ->
- id =
- case act do
- %Activity{} = act -> act.data["id"]
- act when is_map(act) -> act["id"]
- act when is_binary(act) -> act
- end
+ [account.ap_id] ++ build_flag_object(%{statuses: statuses})
+ end
+
+ defp build_flag_object(%{statuses: statuses}) do
+ Enum.map(statuses || [], &build_flag_object/1)
+ end
- activity = Activity.get_by_ap_id_with_object(id)
- actor = User.get_by_ap_id(activity.object.data["actor"])
+ defp build_flag_object(act) when is_map(act) or is_binary(act) do
+ id =
+ case act do
+ %Activity{} = act -> act.data["id"]
+ act when is_map(act) -> act["id"]
+ act when is_binary(act) -> act
+ end
- %{
- "type" => "Note",
- "id" => activity.data["id"],
- "content" => activity.object.data["content"],
- "published" => activity.object.data["published"],
- "actor" => AccountView.render("show.json", %{user: actor})
- }
- end)
+ activity = Activity.get_by_ap_id_with_object(id)
+ actor = User.get_by_ap_id(activity.object.data["actor"])
+
+ %{
+ "type" => "Note",
+ "id" => activity.data["id"],
+ "content" => activity.object.data["content"],
+ "published" => activity.object.data["published"],
+ "actor" => AccountView.render("show.json", %{user: actor})
+ }
end
defp build_flag_object(_), do: []
@@ -679,6 +776,94 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end
#### Report-related helpers
+ def get_reports(params, page, page_size) do
+ 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)
+
+ ActivityPub.fetch_activities([], params, :offset)
+ end
+
+ @spec get_reports_grouped_by_status(%{required(:activity) => String.t()}) :: %{
+ required(:groups) => [
+ %{
+ required(:date) => String.t(),
+ required(:account) => %{},
+ required(:status) => %{},
+ required(:actors) => [%User{}],
+ required(:reports) => [%Activity{}]
+ }
+ ],
+ required(:total) => integer
+ }
+ def get_reports_grouped_by_status(groups) do
+ parsed_groups =
+ groups
+ |> Enum.map(fn entry ->
+ activity =
+ case Jason.decode(entry.activity) do
+ {:ok, activity} -> activity
+ _ -> build_flag_object(entry.activity)
+ end
+
+ parse_report_group(activity)
+ end)
+
+ %{
+ groups: parsed_groups
+ }
+ end
+
+ def parse_report_group(activity) do
+ reports = get_reports_by_status_id(activity["id"])
+ max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"]))
+ actors = Enum.map(reports, & &1.user_actor)
+
+ %{
+ date: max_date.data["published"],
+ account: activity["actor"],
+ status: %{
+ id: activity["id"],
+ content: activity["content"],
+ published: activity["published"]
+ },
+ actors: Enum.uniq(actors),
+ reports: reports
+ }
+ end
+
+ def get_reports_by_status_id(ap_id) do
+ from(a in Activity,
+ where: fragment("(?)->>'type' = 'Flag'", a.data),
+ where: fragment("(?)->'object' @> ?", a.data, ^[%{id: ap_id}])
+ )
+ |> Activity.with_preloaded_user_actor()
+ |> Repo.all()
+ end
+
+ @spec get_reported_activities() :: [
+ %{
+ required(:activity) => String.t(),
+ required(:date) => String.t()
+ }
+ ]
+ def get_reported_activities do
+ from(a in Activity,
+ where: fragment("(?)->>'type' = 'Flag'", a.data),
+ select: %{
+ date: fragment("max(?->>'published') date", a.data),
+ activity:
+ fragment("jsonb_array_elements_text((? #- '{object,0}')->'object') activity", a.data)
+ },
+ group_by: fragment("activity"),
+ order_by: fragment("date DESC")
+ )
+ |> Repo.all()
+ end
def update_report_state(%Activity{} = activity, state)
when state in @strip_status_report_states do
@@ -702,6 +887,18 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> Repo.update()
end
+ def update_report_state(activity_ids, state) when state in @supported_report_states do
+ activities_num = length(activity_ids)
+
+ from(a in Activity, where: a.id in ^activity_ids)
+ |> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)])
+ |> Repo.update_all([])
+ |> case do
+ {^activities_num, _} -> :ok
+ _ -> {:error, activity_ids}
+ end
+ end
+
def update_report_state(_, _), do: {:error, "Unsupported state"}
def strip_report_status_data(activity) do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 30fc01755..8c1318d1b 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
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
@@ -624,19 +625,17 @@ 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)
+ conn
+ |> put_view(ReportView)
+ |> render("index.json", %{reports: Utils.get_reports(params, page, page_size)})
+ end
- reports = ActivityPub.fetch_activities([], params, :offset)
+ def list_grouped_reports(conn, _params) do
+ reports = Utils.get_reported_activities()
conn
|> put_view(ReportView)
- |> render("index.json", %{reports: reports})
+ |> render("index_grouped.json", Utils.get_reports_grouped_by_status(reports))
end
def report_show(conn, %{"id" => id}) do
@@ -649,17 +648,26 @@ 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
diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex
index 101a74c63..ca88595c7 100644
--- a/lib/pleroma/web/admin_api/views/report_view.ex
+++ b/lib/pleroma/web/admin_api/views/report_view.ex
@@ -42,6 +42,26 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
}
end
+ def render("index_grouped.json", %{groups: groups}) do
+ reports =
+ Enum.map(groups, fn group ->
+ %{
+ date: group[:date],
+ account: group[:account],
+ status: group[:status],
+ actors: Enum.map(group[:actors], &merge_account_views/1),
+ reports:
+ group[:reports]
+ |> Enum.map(&Report.extract_report_info(&1))
+ |> Enum.map(&render(__MODULE__, "show.json", &1))
+ }
+ end)
+
+ %{
+ reports: reports
+ }
+ end
+
defp merge_account_views(%User{} = user) do
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
|> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index e57345621..fe6e26a90 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -120,6 +120,25 @@ defmodule Pleroma.Web.CommonAPI do
end
end
+ def react_with_emoji(id, user, emoji) do
+ with %Activity{} = activity <- Activity.get_by_id(id),
+ object <- Object.normalize(activity) do
+ ActivityPub.react_with_emoji(user, object, emoji)
+ else
+ _ ->
+ {:error, dgettext("errors", "Could not add reaction emoji")}
+ end
+ end
+
+ def unreact_with_emoji(id, user, emoji) do
+ with %Activity{} = reaction_activity <- Utils.get_latest_reaction(id, user, emoji) do
+ ActivityPub.unreact_with_emoji(user, reaction_activity.data["id"])
+ else
+ _ ->
+ {:error, dgettext("errors", "Could not remove reaction emoji")}
+ end
+ end
+
def vote(user, %{data: %{"type" => "Question"}} = object, choices) do
with :ok <- validate_not_author(object, user),
:ok <- validate_existing_votes(user, object),
@@ -351,6 +370,13 @@ defmodule Pleroma.Web.CommonAPI do
end
end
+ def update_report_state(activity_ids, state) when is_list(activity_ids) do
+ case Utils.update_report_state(activity_ids, state) do
+ :ok -> {:ok, activity_ids}
+ _ -> {:error, dgettext("errors", "Could not update state")}
+ end
+ end
+
def update_report_state(activity_id, state) do
with %Activity{} = activity <- Activity.get_by_id(activity_id) do
Utils.update_report_state(activity, state)
diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
index 651a99423..8fed3f5bb 100644
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
@@ -7,10 +7,15 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+ alias Pleroma.Activity
alias Pleroma.Conversation.Participation
alias Pleroma.Notification
+ alias Pleroma.Object
alias Pleroma.Plugs.OAuthScopesPlug
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.ConversationView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
@@ -29,6 +34,47 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
+ %Object{data: %{"reactions" => emoji_reactions}} <- Object.normalize(activity) do
+ reactions =
+ emoji_reactions
+ |> Enum.map(fn {emoji, users} ->
+ users = Enum.map(users, &User.get_cached_by_ap_id/1)
+ {emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})}
+ end)
+ |> Enum.into(%{})
+
+ conn
+ |> json(reactions)
+ else
+ _e ->
+ conn
+ |> json(%{})
+ end
+ end
+
+ def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do
+ with {:ok, _activity, _object} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
+ activity <- Activity.get_by_id(activity_id) do
+ conn
+ |> put_view(StatusView)
+ |> render("show.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
+ def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{
+ "id" => activity_id,
+ "emoji" => emoji
+ }) do
+ with {:ok, _activity, _object} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji),
+ activity <- Activity.get_by_id(activity_id) do
+ conn
+ |> put_view(StatusView)
+ |> render("show.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
with %Participation{} = participation <- Participation.get(participation_id),
true <- user.id == participation.user_id do
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index ecf5f744c..9b8b373b8 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -178,8 +178,9 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)
get("/reports", AdminAPIController, :list_reports)
+ get("/grouped_reports", AdminAPIController, :list_grouped_reports)
get("/reports/:id", AdminAPIController, :report_show)
- put("/reports/:id", AdminAPIController, :report_update_state)
+ patch("/reports", AdminAPIController, :reports_update)
post("/reports/:id/respond", AdminAPIController, :report_respond)
put("/statuses/:id", AdminAPIController, :status_update)
@@ -261,6 +262,12 @@ defmodule Pleroma.Web.Router do
end
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
+ pipe_through(:api)
+
+ get("/statuses/:id/emoji_reactions_by", PleromaAPIController, :emoji_reactions_by)
+ end
+
+ scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
scope [] do
pipe_through(:authenticated_api)
@@ -273,6 +280,8 @@ defmodule Pleroma.Web.Router do
pipe_through(:authenticated_api)
patch("/conversations/:id", PleromaAPIController, :update_conversation)
+ post("/statuses/:id/react_with_emoji", PleromaAPIController, :react_with_emoji)
+ post("/statuses/:id/unreact_with_emoji", PleromaAPIController, :unreact_with_emoji)
post("/notifications/read", PleromaAPIController, :read_notification)
patch("/accounts/update_avatar", AccountController, :update_avatar)
diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex
index 5e60c82b0..8ccf15f4b 100644
--- a/lib/pleroma/web/static_fe/static_fe_controller.ex
+++ b/lib/pleroma/web/static_fe/static_fe_controller.ex
@@ -27,6 +27,12 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
defp get_title(_), do: nil
+ defp not_found(conn, message) do
+ conn
+ |> put_status(404)
+ |> render("error.html", %{message: message, meta: ""})
+ end
+
def get_counts(%Activity{} = activity) do
%Object{data: data} = Object.normalize(activity)
@@ -77,10 +83,13 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
render(conn, "conversation.html", %{activities: timeline, meta: meta})
else
- _ ->
+ %Activity{object: %Object{data: data}} ->
conn
- |> put_status(404)
- |> render("error.html", %{message: "Post not found.", meta: ""})
+ |> put_status(:found)
+ |> redirect(external: data["url"] || data["external_url"] || data["id"])
+
+ _ ->
+ not_found(conn, "Post not found.")
end
end
@@ -108,9 +117,33 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
})
_ ->
- conn
- |> put_status(404)
- |> render("error.html", %{message: "User not found.", meta: ""})
+ not_found(conn, "User not found.")
+ end
+ end
+
+ def show(%{assigns: %{object_id: _}} = conn, _params) do
+ url = Helpers.url(conn) <> conn.request_path
+
+ case Activity.get_create_by_object_ap_id_with_object(url) do
+ %Activity{} = activity ->
+ to = Helpers.o_status_path(Pleroma.Web.Endpoint, :notice, activity)
+ redirect(conn, to: to)
+
+ _ ->
+ not_found(conn, "Post not found.")
+ end
+ end
+
+ def show(%{assigns: %{activity_id: _}} = conn, _params) do
+ url = Helpers.url(conn) <> conn.request_path
+
+ case Activity.get_by_ap_id(url) do
+ %Activity{} = activity ->
+ to = Helpers.o_status_path(Pleroma.Web.Endpoint, :notice, activity)
+ redirect(conn, to: to)
+
+ _ ->
+ not_found(conn, "Post not found.")
end
end
@@ -120,5 +153,11 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
def assign_id(%{path_info: ["users", user_id]} = conn, _opts),
do: assign(conn, :username_or_id, user_id)
+ def assign_id(%{path_info: ["objects", object_id]} = conn, _opts),
+ do: assign(conn, :object_id, object_id)
+
+ def assign_id(%{path_info: ["activities", activity_id]} = conn, _opts),
+ do: assign(conn, :activity_id, activity_id)
+
def assign_id(conn, _opts), do: conn
end