summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/pleroma.ex1
-rw-r--r--lib/mix/tasks/pleroma/benchmark.ex3
-rw-r--r--lib/pleroma/config/transfer_task.ex100
-rw-r--r--lib/pleroma/ecto_enums.ex8
-rw-r--r--lib/pleroma/following_relationship.ex51
-rw-r--r--lib/pleroma/plugs/mapped_signature_to_identity_plug.ex6
-rw-r--r--lib/pleroma/plugs/uploaded_media.ex1
-rw-r--r--lib/pleroma/pool/connections.ex2
-rw-r--r--lib/pleroma/user.ex18
-rw-r--r--lib/pleroma/user/query.ex6
-rw-r--r--lib/pleroma/user_relationship.ex47
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex2
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex55
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex6
-rw-r--r--lib/pleroma/web/admin_api/views/report_view.ex7
-rw-r--r--lib/pleroma/web/api_spec.ex2
-rw-r--r--lib/pleroma/web/api_spec/helpers.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/domain_block_operation.ex64
-rw-r--r--lib/pleroma/web/api_spec/schemas/domain_block_request.ex20
-rw-r--r--lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex16
-rw-r--r--lib/pleroma/web/common_api/activity_draft.ex2
-rw-r--r--lib/pleroma/web/common_api/common_api.ex4
-rw-r--r--lib/pleroma/web/controller_helper.ex24
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex15
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex7
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/notification_controller.ex11
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/search_controller.ex24
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/status_controller.ex26
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex40
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex21
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex30
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex11
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/account_controller.ex9
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex27
-rw-r--r--lib/pleroma/web/rich_media/helpers.ex5
-rw-r--r--lib/pleroma/web/router.ex4
36 files changed, 515 insertions, 162 deletions
diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex
index 4dfcc32e7..3ad6edbfb 100644
--- a/lib/mix/pleroma.ex
+++ b/lib/mix/pleroma.ex
@@ -5,7 +5,6 @@
defmodule Mix.Pleroma do
@doc "Common functions to be reused in mix tasks"
def start_pleroma do
- Mix.Task.run("app.start")
Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
if Pleroma.Config.get(:env) != :test do
diff --git a/lib/mix/tasks/pleroma/benchmark.ex b/lib/mix/tasks/pleroma/benchmark.ex
index dd2b9c8f2..6ab7fe8ef 100644
--- a/lib/mix/tasks/pleroma/benchmark.ex
+++ b/lib/mix/tasks/pleroma/benchmark.ex
@@ -67,7 +67,8 @@ defmodule Mix.Tasks.Pleroma.Benchmark do
Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
activities: activities,
for: user,
- as: :activity
+ as: :activity,
+ skip_relationships: true
})
end
},
diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex
index 936bc9ab1..3871e1cbb 100644
--- a/lib/pleroma/config/transfer_task.ex
+++ b/lib/pleroma/config/transfer_task.ex
@@ -54,10 +54,19 @@ defmodule Pleroma.Config.TransferTask do
[:pleroma, nil, :prometheus]
end
+ {logger, other} =
+ (Repo.all(ConfigDB) ++ deleted_settings)
+ |> Enum.map(&transform_and_merge/1)
+ |> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end)
+
+ logger
+ |> Enum.sort()
+ |> Enum.each(&configure/1)
+
started_applications = Application.started_applications()
- (Repo.all(ConfigDB) ++ deleted_settings)
- |> Enum.map(&merge_and_update/1)
+ other
+ |> Enum.map(&update/1)
|> Enum.uniq()
|> Enum.reject(&(&1 in reject_restart))
|> maybe_set_pleroma_last()
@@ -81,51 +90,66 @@ defmodule Pleroma.Config.TransferTask do
end
end
- defp group_for_restart(:logger, key, _, merged_value) do
- # change logger configuration in runtime, without restart
- if Keyword.keyword?(merged_value) and
- key not in [:compile_time_application, :backends, :compile_time_purge_matching] do
- Logger.configure_backend(key, merged_value)
- else
- Logger.configure([{key, merged_value}])
- end
+ defp transform_and_merge(%{group: group, key: key, value: value} = setting) do
+ group = ConfigDB.from_string(group)
+ key = ConfigDB.from_string(key)
+ value = ConfigDB.from_binary(value)
- nil
- end
+ default = Config.Holder.default_config(group, key)
- defp group_for_restart(group, _, _, _) when group != :pleroma, do: group
+ merged =
+ cond do
+ Ecto.get_meta(setting, :state) == :deleted -> default
+ can_be_merged?(default, value) -> ConfigDB.merge_group(group, key, default, value)
+ true -> value
+ end
- defp group_for_restart(group, key, value, _) do
- if pleroma_need_restart?(group, key, value), do: group
+ {group, key, value, merged}
end
- defp merge_and_update(setting) do
- try do
- key = ConfigDB.from_string(setting.key)
- group = ConfigDB.from_string(setting.group)
+ # change logger configuration in runtime, without restart
+ defp configure({:quack, key, _, merged}) do
+ Logger.configure_backend(Quack.Logger, [{key, merged}])
+ :ok = update_env(:quack, key, merged)
+ end
- default = Config.Holder.default_config(group, key)
- value = ConfigDB.from_binary(setting.value)
+ defp configure({_, :backends, _, merged}) do
+ # removing current backends
+ Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1)
- merged_value =
- cond do
- Ecto.get_meta(setting, :state) == :deleted -> default
- can_be_merged?(default, value) -> ConfigDB.merge_group(group, key, default, value)
- true -> value
- end
+ Enum.each(merged, &Logger.add_backend/1)
- :ok = update_env(group, key, merged_value)
+ :ok = update_env(:logger, :backends, merged)
+ end
- group_for_restart(group, key, value, merged_value)
+ defp configure({group, key, _, merged}) do
+ merged =
+ if key == :console do
+ put_in(merged[:format], merged[:format] <> "\n")
+ else
+ merged
+ end
+
+ backend =
+ if key == :ex_syslogger,
+ do: {ExSyslogger, :ex_syslogger},
+ else: key
+
+ Logger.configure_backend(backend, merged)
+ :ok = update_env(:logger, group, merged)
+ end
+
+ defp update({group, key, value, merged}) do
+ try do
+ :ok = update_env(group, key, merged)
+
+ if group != :pleroma or pleroma_need_restart?(group, key, value), do: group
rescue
error ->
error_msg =
- "updating env causes error, group: " <>
- inspect(setting.group) <>
- " key: " <>
- inspect(setting.key) <>
- " value: " <>
- inspect(ConfigDB.from_binary(setting.value)) <> " error: " <> inspect(error)
+ "updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{
+ inspect(value)
+ } error: #{inspect(error)}"
Logger.warn(error_msg)
@@ -133,6 +157,9 @@ defmodule Pleroma.Config.TransferTask do
end
end
+ defp update_env(group, key, nil), do: Application.delete_env(group, key)
+ defp update_env(group, key, value), do: Application.put_env(group, key, value)
+
@spec pleroma_need_restart?(atom(), atom(), any()) :: boolean()
def pleroma_need_restart?(group, key, value) do
group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value)
@@ -150,9 +177,6 @@ defmodule Pleroma.Config.TransferTask do
end)
end
- defp update_env(group, key, nil), do: Application.delete_env(group, key)
- defp update_env(group, key, value), do: Application.put_env(group, key, value)
-
defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env)
defp restart(started_applications, app, _) do
diff --git a/lib/pleroma/ecto_enums.ex b/lib/pleroma/ecto_enums.ex
index d9b601223..6fc47620c 100644
--- a/lib/pleroma/ecto_enums.ex
+++ b/lib/pleroma/ecto_enums.ex
@@ -4,10 +4,16 @@
import EctoEnum
-defenum(UserRelationshipTypeEnum,
+defenum(Pleroma.UserRelationship.Type,
block: 1,
mute: 2,
reblog_mute: 3,
notification_mute: 4,
inverse_subscription: 5
)
+
+defenum(Pleroma.FollowingRelationship.State,
+ follow_pending: 1,
+ follow_accept: 2,
+ follow_reject: 3
+)
diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex
index a9538ea4e..9ccf40495 100644
--- a/lib/pleroma/following_relationship.ex
+++ b/lib/pleroma/following_relationship.ex
@@ -8,12 +8,13 @@ defmodule Pleroma.FollowingRelationship do
import Ecto.Changeset
import Ecto.Query
+ alias Ecto.Changeset
alias FlakeId.Ecto.CompatType
alias Pleroma.Repo
alias Pleroma.User
schema "following_relationships" do
- field(:state, :string, default: "accept")
+ field(:state, Pleroma.FollowingRelationship.State, default: :follow_pending)
belongs_to(:follower, User, type: CompatType)
belongs_to(:following, User, type: CompatType)
@@ -27,6 +28,18 @@ defmodule Pleroma.FollowingRelationship do
|> put_assoc(:follower, attrs.follower)
|> put_assoc(:following, attrs.following)
|> validate_required([:state, :follower, :following])
+ |> unique_constraint(:follower_id,
+ name: :following_relationships_follower_id_following_id_index
+ )
+ |> validate_not_self_relationship()
+ end
+
+ def state_to_enum(state) when state in ["pending", "accept", "reject"] do
+ String.to_existing_atom("follow_#{state}")
+ end
+
+ def state_to_enum(state) do
+ raise "State is not convertible to Pleroma.FollowingRelationship.State: #{state}"
end
def get(%User{} = follower, %User{} = following) do
@@ -35,7 +48,7 @@ defmodule Pleroma.FollowingRelationship do
|> Repo.one()
end
- def update(follower, following, "reject"), do: unfollow(follower, following)
+ def update(follower, following, :follow_reject), do: unfollow(follower, following)
def update(%User{} = follower, %User{} = following, state) do
case get(follower, following) do
@@ -50,7 +63,7 @@ defmodule Pleroma.FollowingRelationship do
end
end
- def follow(%User{} = follower, %User{} = following, state \\ "accept") do
+ def follow(%User{} = follower, %User{} = following, state \\ :follow_accept) do
%__MODULE__{}
|> changeset(%{follower: follower, following: following, state: state})
|> Repo.insert(on_conflict: :nothing)
@@ -80,7 +93,7 @@ defmodule Pleroma.FollowingRelationship do
def get_follow_requests(%User{id: id}) do
__MODULE__
|> join(:inner, [r], f in assoc(r, :follower))
- |> where([r], r.state == "pending")
+ |> where([r], r.state == ^:follow_pending)
|> where([r], r.following_id == ^id)
|> select([r, f], f)
|> Repo.all()
@@ -88,7 +101,7 @@ defmodule Pleroma.FollowingRelationship do
def following?(%User{id: follower_id}, %User{id: followed_id}) do
__MODULE__
- |> where(follower_id: ^follower_id, following_id: ^followed_id, state: "accept")
+ |> where(follower_id: ^follower_id, following_id: ^followed_id, state: ^:follow_accept)
|> Repo.exists?()
end
@@ -97,7 +110,7 @@ defmodule Pleroma.FollowingRelationship do
__MODULE__
|> join(:inner, [r], u in User, on: r.following_id == u.id)
|> where([r], r.follower_id == ^user.id)
- |> where([r], r.state == "accept")
+ |> where([r], r.state == ^:follow_accept)
|> select([r, u], u.follower_address)
|> Repo.all()
@@ -157,4 +170,30 @@ defmodule Pleroma.FollowingRelationship do
fr -> fr.follower_id == follower.id and fr.following_id == following.id
end)
end
+
+ defp validate_not_self_relationship(%Changeset{} = changeset) do
+ changeset
+ |> validate_follower_id_following_id_inequality()
+ |> validate_following_id_follower_id_inequality()
+ end
+
+ defp validate_follower_id_following_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :follower_id, fn _, follower_id ->
+ if follower_id == get_field(changeset, :following_id) do
+ [source_id: "can't be equal to following_id"]
+ else
+ []
+ end
+ end)
+ end
+
+ defp validate_following_id_follower_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :following_id, fn _, following_id ->
+ if following_id == get_field(changeset, :follower_id) do
+ [target_id: "can't be equal to follower_id"]
+ else
+ []
+ end
+ end)
+ end
end
diff --git a/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex b/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex
index 4f124ed4d..84b7c5d83 100644
--- a/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex
+++ b/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex
@@ -42,13 +42,13 @@ defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlug do
else
{:user_match, false} ->
Logger.debug("Failed to map identity from signature (payload actor mismatch)")
- Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
+ Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{inspect(actor)}")
assign(conn, :valid_signature, false)
# remove me once testsuite uses mapped capabilities instead of what we do now
{:user, nil} ->
Logger.debug("Failed to map identity from signature (lookup failure)")
- Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
+ Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{actor}")
conn
end
end
@@ -60,7 +60,7 @@ defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlug do
else
_ ->
Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
- Logger.debug("key_id=#{key_id_from_conn(conn)}")
+ Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
assign(conn, :valid_signature, false)
end
end
diff --git a/lib/pleroma/plugs/uploaded_media.ex b/lib/pleroma/plugs/uploaded_media.ex
index 36ff024a7..94147e0c4 100644
--- a/lib/pleroma/plugs/uploaded_media.ex
+++ b/lib/pleroma/plugs/uploaded_media.ex
@@ -41,6 +41,7 @@ defmodule Pleroma.Plugs.UploadedMedia do
conn ->
conn
end
+ |> merge_resp_headers([{"content-security-policy", "sandbox"}])
config = Pleroma.Config.get(Pleroma.Upload)
diff --git a/lib/pleroma/pool/connections.ex b/lib/pleroma/pool/connections.ex
index 4d4ba913c..acafe1bea 100644
--- a/lib/pleroma/pool/connections.ex
+++ b/lib/pleroma/pool/connections.ex
@@ -243,7 +243,7 @@ defmodule Pleroma.Pool.Connections do
@impl true
def handle_info({:DOWN, _ref, :process, conn_pid, reason}, state) do
- Logger.debug("received DOWM message for #{inspect(conn_pid)} reason -> #{inspect(reason)}")
+ Logger.debug("received DOWN message for #{inspect(conn_pid)} reason -> #{inspect(reason)}")
state =
with {key, conn} <- find_conn(state.conns, conn_pid) do
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 71c8c3a4e..670ce397b 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -700,7 +700,7 @@ defmodule Pleroma.User do
@spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
def maybe_direct_follow(%User{} = follower, %User{local: true, locked: true} = followed) do
- follow(follower, followed, "pending")
+ follow(follower, followed, :follow_pending)
end
def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) do
@@ -720,14 +720,14 @@ defmodule Pleroma.User do
def follow_all(follower, followeds) do
followeds
|> Enum.reject(fn followed -> blocks?(follower, followed) || blocks?(followed, follower) end)
- |> Enum.each(&follow(follower, &1, "accept"))
+ |> Enum.each(&follow(follower, &1, :follow_accept))
set_cache(follower)
end
defdelegate following(user), to: FollowingRelationship
- def follow(%User{} = follower, %User{} = followed, state \\ "accept") do
+ def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do
deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked])
cond do
@@ -754,7 +754,7 @@ defmodule Pleroma.User do
def unfollow(%User{} = follower, %User{} = followed) do
case get_follow_state(follower, followed) do
- state when state in ["accept", "pending"] ->
+ state when state in [:follow_pending, :follow_accept] ->
FollowingRelationship.unfollow(follower, followed)
{:ok, followed} = update_follower_count(followed)
@@ -772,6 +772,7 @@ defmodule Pleroma.User do
defdelegate following?(follower, followed), to: FollowingRelationship
+ @doc "Returns follow state as Pleroma.FollowingRelationship.State value"
def get_follow_state(%User{} = follower, %User{} = following) do
following_relationship = FollowingRelationship.get(follower, following)
get_follow_state(follower, following, following_relationship)
@@ -785,8 +786,11 @@ defmodule Pleroma.User do
case {following_relationship, following.local} do
{nil, false} ->
case Utils.fetch_latest_follow(follower, following) do
- %{data: %{"state" => state}} when state in ["pending", "accept"] -> state
- _ -> nil
+ %Activity{data: %{"state" => state}} when state in ["pending", "accept"] ->
+ FollowingRelationship.state_to_enum(state)
+
+ _ ->
+ nil
end
{%{state: state}, _} ->
@@ -1285,7 +1289,7 @@ defmodule Pleroma.User do
def blocks?(%User{} = user, %User{} = target) do
blocks_user?(user, target) ||
- (!User.following?(user, target) && blocks_domain?(user, target))
+ (blocks_domain?(user, target) and not User.following?(user, target))
end
def blocks_user?(%User{} = user, %User{} = target) do
diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex
index 884e33039..ec88088cf 100644
--- a/lib/pleroma/user/query.ex
+++ b/lib/pleroma/user/query.ex
@@ -148,7 +148,7 @@ defmodule Pleroma.User.Query do
as: :relationships,
on: r.following_id == ^id and r.follower_id == u.id
)
- |> where([relationships: r], r.state == "accept")
+ |> where([relationships: r], r.state == ^:follow_accept)
end
defp compose_query({:friends, %User{id: id}}, query) do
@@ -158,7 +158,7 @@ defmodule Pleroma.User.Query do
as: :relationships,
on: r.following_id == u.id and r.follower_id == ^id
)
- |> where([relationships: r], r.state == "accept")
+ |> where([relationships: r], r.state == ^:follow_accept)
end
defp compose_query({:recipients_from_activity, to}, query) do
@@ -173,7 +173,7 @@ defmodule Pleroma.User.Query do
)
|> where(
[u, following: f, relationships: r],
- u.ap_id in ^to or (f.follower_address in ^to and r.state == "accept")
+ u.ap_id in ^to or (f.follower_address in ^to and r.state == ^:follow_accept)
)
|> distinct(true)
end
diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex
index 18a5eec72..235ad427c 100644
--- a/lib/pleroma/user_relationship.ex
+++ b/lib/pleroma/user_relationship.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.UserRelationship do
import Ecto.Changeset
import Ecto.Query
+ alias Ecto.Changeset
alias Pleroma.FollowingRelationship
alias Pleroma.Repo
alias Pleroma.User
@@ -16,12 +17,12 @@ defmodule Pleroma.UserRelationship do
schema "user_relationships" do
belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
belongs_to(:target, User, type: FlakeId.Ecto.CompatType)
- field(:relationship_type, UserRelationshipTypeEnum)
+ field(:relationship_type, Pleroma.UserRelationship.Type)
timestamps(updated_at: false)
end
- for relationship_type <- Keyword.keys(UserRelationshipTypeEnum.__enum_map__()) do
+ for relationship_type <- Keyword.keys(Pleroma.UserRelationship.Type.__enum_map__()) do
# `def create_block/2`, `def create_mute/2`, `def create_reblog_mute/2`,
# `def create_notification_mute/2`, `def create_inverse_subscription/2`
def unquote(:"create_#{relationship_type}")(source, target),
@@ -40,7 +41,7 @@ defmodule Pleroma.UserRelationship do
def user_relationship_types, do: Keyword.keys(user_relationship_mappings())
- def user_relationship_mappings, do: UserRelationshipTypeEnum.__enum_map__()
+ def user_relationship_mappings, do: Pleroma.UserRelationship.Type.__enum_map__()
def changeset(%UserRelationship{} = user_relationship, params \\ %{}) do
user_relationship
@@ -129,17 +130,27 @@ defmodule Pleroma.UserRelationship do
end
@doc ":relationships option for StatusView / AccountView / NotificationView"
- def view_relationships_option(nil = _reading_user, _actors) do
+ def view_relationships_option(reading_user, actors, opts \\ [])
+
+ def view_relationships_option(nil = _reading_user, _actors, _opts) do
%{user_relationships: [], following_relationships: []}
end
- def view_relationships_option(%User{} = reading_user, actors) do
+ def view_relationships_option(%User{} = reading_user, actors, opts) do
+ {source_to_target_rel_types, target_to_source_rel_types} =
+ if opts[:source_mutes_only] do
+ # This option is used for rendering statuses (FE needs `muted` flag for each one anyways)
+ {[:mute], []}
+ else
+ {[:block, :mute, :notification_mute, :reblog_mute], [:block, :inverse_subscription]}
+ end
+
user_relationships =
UserRelationship.dictionary(
[reading_user],
actors,
- [:block, :mute, :notification_mute, :reblog_mute],
- [:block, :inverse_subscription]
+ source_to_target_rel_types,
+ target_to_source_rel_types
)
following_relationships = FollowingRelationship.all_between_user_sets([reading_user], actors)
@@ -147,18 +158,26 @@ defmodule Pleroma.UserRelationship do
%{user_relationships: user_relationships, following_relationships: following_relationships}
end
- defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
+ defp validate_not_self_relationship(%Changeset{} = changeset) do
changeset
- |> validate_change(:target_id, fn _, target_id ->
- if target_id == get_field(changeset, :source_id) do
- [target_id: "can't be equal to source_id"]
+ |> validate_source_id_target_id_inequality()
+ |> validate_target_id_source_id_inequality()
+ end
+
+ defp validate_source_id_target_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :source_id, fn _, source_id ->
+ if source_id == get_field(changeset, :target_id) do
+ [source_id: "can't be equal to target_id"]
else
[]
end
end)
- |> validate_change(:source_id, fn _, source_id ->
- if source_id == get_field(changeset, :target_id) do
- [source_id: "can't be equal to target_id"]
+ end
+
+ defp validate_target_id_source_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :target_id, fn _, target_id ->
+ if target_id == get_field(changeset, :source_id) do
+ [target_id: "can't be equal to source_id"]
else
[]
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 0b4892501..4a56beb73 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -722,7 +722,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- defp fetch_activities_for_context_query(context, opts) do
+ def fetch_activities_for_context_query(context, opts) do
public = [Constants.as_public()]
recipients =
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index becc35ea3..ad77a5037 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -206,16 +206,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("conversation", context)
end
+ defp add_if_present(map, _key, nil), do: map
+
+ defp add_if_present(map, key, value) do
+ Map.put(map, key, value)
+ end
+
def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
attachments =
Enum.map(attachment, fn data ->
- media_type = data["mediaType"] || data["mimeType"]
- href = data["url"] || data["href"]
- url = [%{"type" => "Link", "mediaType" => media_type, "href" => href}]
+ url =
+ cond do
+ is_list(data["url"]) -> List.first(data["url"])
+ is_map(data["url"]) -> data["url"]
+ true -> nil
+ end
- data
- |> Map.put("mediaType", media_type)
- |> Map.put("url", url)
+ media_type =
+ cond do
+ is_map(url) && is_binary(url["mediaType"]) -> url["mediaType"]
+ is_binary(data["mediaType"]) -> data["mediaType"]
+ is_binary(data["mimeType"]) -> data["mimeType"]
+ true -> nil
+ end
+
+ href =
+ cond do
+ is_map(url) && is_binary(url["href"]) -> url["href"]
+ is_binary(data["url"]) -> data["url"]
+ is_binary(data["href"]) -> data["href"]
+ end
+
+ attachment_url =
+ %{"href" => href}
+ |> add_if_present("mediaType", media_type)
+ |> add_if_present("type", Map.get(url || %{}, "type"))
+
+ %{"url" => [attachment_url]}
+ |> add_if_present("mediaType", media_type)
+ |> add_if_present("type", data["type"])
+ |> add_if_present("name", data["name"])
end)
Map.put(object, "attachment", attachments)
@@ -495,7 +525,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
{_, {:ok, _}} <-
{:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")},
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+ {:ok, _relationship} <-
+ FollowingRelationship.update(follower, followed, :follow_accept) do
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
@@ -505,7 +536,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
else
{:user_blocked, true} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
ActivityPub.reject(%{
to: [follower.ap_id],
@@ -516,7 +547,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:follow, {:error, _}} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
ActivityPub.reject(%{
to: [follower.ap_id],
@@ -526,7 +557,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
})
{:user_locked, true} ->
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "pending")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_pending)
:noop
end
@@ -546,7 +577,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept) do
ActivityPub.accept(%{
to: follow_activity.data["to"],
type: "Accept",
@@ -569,7 +600,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
{:ok, activity} <-
ActivityPub.reject(%{
to: follow_activity.data["to"],
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index fdbd24acb..831c3bd02 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -258,7 +258,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
conn
|> put_view(Pleroma.Web.AdminAPI.StatusView)
- |> render("index.json", %{activities: activities, as: :activity})
+ |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
end
def list_user_statuses(conn, %{"nickname" => nickname} = params) do
@@ -277,7 +277,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
conn
|> put_view(StatusView)
- |> render("index.json", %{activities: activities, as: :activity})
+ |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
else
_ -> {:error, :not_found}
end
@@ -812,7 +812,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
conn
|> put_view(Pleroma.Web.AdminAPI.StatusView)
- |> render("index.json", %{activities: activities, as: :activity})
+ |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
end
def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex
index ca0bcebc7..d50969b2a 100644
--- a/lib/pleroma/web/admin_api/views/report_view.ex
+++ b/lib/pleroma/web/admin_api/views/report_view.ex
@@ -38,7 +38,12 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
actor: merge_account_views(user),
content: content,
created_at: created_at,
- statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}),
+ statuses:
+ StatusView.render("index.json", %{
+ activities: statuses,
+ as: :activity,
+ skip_relationships: false
+ }),
state: report.data["state"],
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
}
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
index 41e48a085..3890489e3 100644
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -31,7 +31,7 @@ defmodule Pleroma.Web.ApiSpec do
password: %OpenApiSpex.OAuthFlow{
authorizationUrl: "/oauth/authorize",
tokenUrl: "/oauth/token",
- scopes: %{"read" => "read"}
+ scopes: %{"read" => "read", "write" => "write", "follow" => "follow"}
}
}
}
diff --git a/lib/pleroma/web/api_spec/helpers.ex b/lib/pleroma/web/api_spec/helpers.ex
index 35cf4c0d8..7348dcbee 100644
--- a/lib/pleroma/web/api_spec/helpers.ex
+++ b/lib/pleroma/web/api_spec/helpers.ex
@@ -4,7 +4,7 @@
defmodule Pleroma.Web.ApiSpec.Helpers do
def request_body(description, schema_ref, opts \\ []) do
- media_types = ["application/json", "multipart/form-data"]
+ media_types = ["application/json", "multipart/form-data", "application/x-www-form-urlencoded"]
content =
media_types
diff --git a/lib/pleroma/web/api_spec/operations/domain_block_operation.ex b/lib/pleroma/web/api_spec/operations/domain_block_operation.ex
new file mode 100644
index 000000000..dd14837c3
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/domain_block_operation.ex
@@ -0,0 +1,64 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.DomainBlockOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Helpers
+ alias Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest
+ alias Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["domain_blocks"],
+ summary: "Fetch domain blocks",
+ description: "View domains the user has blocked.",
+ security: [%{"oAuth" => ["follow", "read:blocks"]}],
+ operationId: "DomainBlockController.index",
+ responses: %{
+ 200 => Operation.response("Domain blocks", "application/json", DomainBlocksResponse)
+ }
+ }
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["domain_blocks"],
+ summary: "Block a domain",
+ description: """
+ Block a domain to:
+
+ - hide all public posts from it
+ - hide all notifications from it
+ - remove all followers from it
+ - prevent following new users from it (but does not remove existing follows)
+ """,
+ operationId: "DomainBlockController.create",
+ requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
+ security: [%{"oAuth" => ["follow", "write:blocks"]}],
+ responses: %{
+ 200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
+ }
+ }
+ end
+
+ def delete_operation do
+ %Operation{
+ tags: ["domain_blocks"],
+ summary: "Unblock a domain",
+ description: "Remove a domain block, if it exists in the user's array of blocked domains.",
+ operationId: "DomainBlockController.delete",
+ requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
+ security: [%{"oAuth" => ["follow", "write:blocks"]}],
+ responses: %{
+ 200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/schemas/domain_block_request.ex b/lib/pleroma/web/api_spec/schemas/domain_block_request.ex
new file mode 100644
index 000000000..ee9238361
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/domain_block_request.ex
@@ -0,0 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest do
+ alias OpenApiSpex.Schema
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "DomainBlockRequest",
+ type: :object,
+ properties: %{
+ domain: %Schema{type: :string}
+ },
+ required: [:domain],
+ example: %{
+ "domain" => "facebook.com"
+ }
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex b/lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex
new file mode 100644
index 000000000..d895aca4e
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex
@@ -0,0 +1,16 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse do
+ require OpenApiSpex
+ alias OpenApiSpex.Schema
+
+ OpenApiSpex.schema(%{
+ title: "DomainBlocksResponse",
+ description: "Response schema for domain blocks",
+ type: :array,
+ items: %Schema{type: :string},
+ example: ["google.com", "facebook.com"]
+ })
+end
diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex
index c4356f93b..c1cd15bb2 100644
--- a/lib/pleroma/web/common_api/activity_draft.ex
+++ b/lib/pleroma/web/common_api/activity_draft.ex
@@ -187,7 +187,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
end
defp preview?(draft) do
- preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"]) || false
+ preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"])
%__MODULE__{draft | preview?: preview?}
end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 39e15adbf..2f13daf0c 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.CommonAPI do
with {:ok, follower} <- User.follow(follower, followed),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept),
{:ok, _activity} <-
ActivityPub.accept(%{
to: [follower.ap_id],
@@ -83,7 +83,7 @@ defmodule Pleroma.Web.CommonAPI do
def reject_follow_request(follower, followed) do
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
{:ok, _activity} <-
ActivityPub.reject(%{
to: [follower.ap_id],
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index b49523ec3..4780081b2 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -5,10 +5,18 @@
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
- # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
+ alias Pleroma.Config
+
+ # As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
- def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
- def truthy_param?(value), do: value not in @falsy_param_values
+
+ def explicitly_falsy_param?(value), do: value in @falsy_param_values
+
+ # Note: `nil` and `""` are considered falsy values in Pleroma
+ def falsy_param?(value),
+ do: explicitly_falsy_param?(value) or value in [nil, ""]
+
+ def truthy_param?(value), do: not falsy_param?(value)
def json_response(conn, status, json) do
conn
@@ -96,4 +104,14 @@ defmodule Pleroma.Web.ControllerHelper do
def put_if_exist(map, _key, nil), do: map
def put_if_exist(map, key, value), do: Map.put(map, key, value)
+
+ @doc "Whether to skip rendering `[:account][:pleroma][:relationship]`for statuses/notifications"
+ def skip_relationships?(params) do
+ if Config.get([:extensions, :output_relationships_in_statuses_by_default]) do
+ false
+ else
+ # BREAKING: older PleromaFE versions do not send this param but _do_ expect relationships.
+ not truthy_param?(params["with_relationships"])
+ end
+ end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 21bc3d5a5..7da1a11f6 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -6,7 +6,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [add_link_headers: 2, truthy_param?: 1, assign_account_by_id: 2, json_response: 3]
+ only: [
+ add_link_headers: 2,
+ truthy_param?: 1,
+ assign_account_by_id: 2,
+ json_response: 3,
+ skip_relationships?: 1
+ ]
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter
@@ -237,7 +243,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(activities)
|> put_view(StatusView)
- |> render("index.json", activities: activities, for: reading_user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: reading_user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
else
_e -> render_error(conn, :not_found, "Can't find user")
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
index e4156cbe6..84de79413 100644
--- a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
@@ -8,6 +8,9 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User
+ plug(OpenApiSpex.Plug.CastAndValidate)
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.DomainBlockOperation
+
plug(
OAuthScopesPlug,
%{scopes: ["follow", "read:blocks"]} when action == :index
@@ -26,13 +29,13 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
end
@doc "POST /api/v1/domain_blocks"
- def create(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
+ def create(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
User.block_domain(blocker, domain)
json(conn, %{})
end
@doc "DELETE /api/v1/domain_blocks"
- def delete(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
+ def delete(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
User.unblock_domain(blocker, domain)
json(conn, %{})
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
index 0c9218454..7fb536b09 100644
--- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.MastodonAPI.NotificationController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
alias Pleroma.Notification
alias Pleroma.Plugs.OAuthScopesPlug
@@ -45,7 +45,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
conn
|> add_link_headers(notifications)
- |> render("index.json", notifications: notifications, for: user)
+ |> render("index.json",
+ notifications: notifications,
+ for: user,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/notifications/:id
@@ -66,7 +70,8 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
json(conn, %{})
end
- # POST /api/v1/notifications/dismiss
+ # POST /api/v1/notifications/:id/dismiss
+ # POST /api/v1/notifications/dismiss (deprecated)
def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
with {:ok, _notif} <- Notification.dismiss(user, id) do
json(conn, %{})
diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
index fcab4ef63..c258742dd 100644
--- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
@@ -5,13 +5,14 @@
defmodule Pleroma.Web.MastodonAPI.SearchController do
use Pleroma.Web, :controller
+ import Pleroma.Web.ControllerHelper, only: [fetch_integer_param: 2, skip_relationships?: 1]
+
alias Pleroma.Activity
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
- alias Pleroma.Web.ControllerHelper
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.StatusView
@@ -66,10 +67,11 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
defp search_options(params, user) do
[
+ skip_relationships: skip_relationships?(params),
resolve: params["resolve"] == "true",
following: params["following"] == "true",
- limit: ControllerHelper.fetch_integer_param(params, "limit"),
- offset: ControllerHelper.fetch_integer_param(params, "offset"),
+ limit: fetch_integer_param(params, "limit"),
+ offset: fetch_integer_param(params, "offset"),
type: params["type"],
author: get_author(params),
for_user: user
@@ -79,12 +81,24 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
defp resource_search(_, "accounts", query, options) do
accounts = with_fallback(fn -> User.search(query, options) end)
- AccountView.render("index.json", users: accounts, for: options[:for_user], as: :user)
+
+ AccountView.render("index.json",
+ users: accounts,
+ for: options[:for_user],
+ as: :user,
+ skip_relationships: false
+ )
end
defp resource_search(_, "statuses", query, options) do
statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
- StatusView.render("index.json", activities: statuses, for: options[:for_user], as: :activity)
+
+ StatusView.render("index.json",
+ activities: statuses,
+ for: options[:for_user],
+ as: :activity,
+ skip_relationships: options[:skip_relationships]
+ )
end
defp resource_search(:v2, "hashtags", query, _options) do
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
index ec8f0d8a0..397dd10e3 100644
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -5,7 +5,8 @@
defmodule Pleroma.Web.MastodonAPI.StatusController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [try_render: 3, add_link_headers: 2]
+ import Pleroma.Web.ControllerHelper,
+ only: [try_render: 3, add_link_headers: 2, skip_relationships?: 1]
require Ecto.Query
@@ -101,7 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
`ids` query param is required
"""
- def index(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
+ def index(%{assigns: %{user: user}} = conn, %{"ids" => ids} = params) do
limit = 100
activities =
@@ -110,7 +111,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|> Activity.all_by_ids_with_object()
|> Enum.filter(&Visibility.visible_for_user?(&1, user))
- render(conn, "index.json", activities: activities, for: user, as: :activity)
+ render(conn, "index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
@doc """
@@ -360,7 +366,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
conn
|> add_link_headers(activities)
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
@doc "GET /api/v1/bookmarks"
@@ -378,6 +389,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
conn
|> add_link_headers(bookmarks)
- |> render("index.json", %{activities: activities, for: user, as: :activity})
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index 91f41416d..b3c58005e 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1]
+ only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1, skip_relationships?: 1]
alias Pleroma.Pagination
alias Pleroma.Plugs.OAuthScopesPlug
@@ -14,9 +14,8 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
- # TODO: Replace with a macro when there is a Phoenix release with
+ # TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
- # in it
plug(RateLimiter, [name: :timeline, bucket_name: :direct_timeline] when action == :direct)
plug(RateLimiter, [name: :timeline, bucket_name: :public_timeline] when action == :public)
@@ -49,7 +48,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
conn
|> add_link_headers(activities)
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/timelines/direct
@@ -68,7 +72,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
conn
|> add_link_headers(activities)
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/timelines/public
@@ -95,7 +104,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
conn
|> add_link_headers(activities, %{"local" => local_only})
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
else
render_error(conn, :unauthorized, "authorization required for timeline view")
end
@@ -140,7 +154,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
conn
|> add_link_headers(activities, %{"local" => local_only})
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/timelines/list/:list_id
@@ -164,7 +183,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> ActivityPub.fetch_activities_bounded(following, params)
|> Enum.reverse()
- render(conn, "index.json", activities: activities, for: user, as: :activity)
+ render(conn, "index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
else
_e -> render_error(conn, :forbidden, "Error.")
end
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 99e62f580..8fb96a22a 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -15,6 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
def render("index.json", %{users: users} = opts) do
reading_user = opts[:for]
+ # Note: :skip_relationships option is currently intentionally not supported for accounts
relationships_opt =
cond do
Map.has_key?(opts, :relationships) ->
@@ -73,7 +74,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
followed_by =
if following_relationships do
case FollowingRelationship.find(following_relationships, target, reading_user) do
- %{state: "accept"} -> true
+ %{state: :follow_accept} -> true
_ -> false
end
else
@@ -83,7 +84,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
# NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
%{
id: to_string(target.id),
- following: follow_state == "accept",
+ following: follow_state == :follow_accept,
followed_by: followed_by,
blocking:
UserRelationship.exists?(
@@ -125,7 +126,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
reading_user,
&User.subscribed_to?(&2, &1)
),
- requested: follow_state == "pending",
+ requested: follow_state == :follow_pending,
domain_blocking: User.blocks_domain?(reading_user, target),
showing_reblogs:
not UserRelationship.exists?(
@@ -192,11 +193,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
end)
relationship =
- render("relationship.json", %{
- user: opts[:for],
- target: user,
- relationships: opts[:relationships]
- })
+ if opts[:skip_relationships] do
+ %{}
+ else
+ render("relationship.json", %{
+ user: opts[:for],
+ target: user,
+ relationships: opts[:relationships]
+ })
+ end
%{
id: to_string(user.id),
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index ae87d4701..734ffbf39 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -51,14 +51,15 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|> Enum.filter(& &1)
|> Kernel.++(move_activities_targets)
- UserRelationship.view_relationships_option(reading_user, actors)
+ UserRelationship.view_relationships_option(reading_user, actors,
+ source_mutes_only: opts[:skip_relationships]
+ )
end
- opts = %{
- for: reading_user,
- parent_activities: parent_activities,
- relationships: relationships_opt
- }
+ opts =
+ opts
+ |> Map.put(:parent_activities, parent_activities)
+ |> Map.put(:relationships, relationships_opt)
safe_render_many(notifications, NotificationView, "show.json", opts)
end
@@ -82,12 +83,16 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
mastodon_type = Activity.mastodon_notification_type(activity)
+ render_opts = %{
+ relationships: opts[:relationships],
+ skip_relationships: opts[:skip_relationships]
+ }
+
with %{id: _} = account <-
- AccountView.render("show.json", %{
- user: actor,
- for: reading_user,
- relationships: opts[:relationships]
- }) do
+ AccountView.render(
+ "show.json",
+ Map.merge(render_opts, %{user: actor, for: reading_user})
+ ) do
response = %{
id: to_string(notification.id),
type: mastodon_type,
@@ -98,8 +103,6 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
}
}
- render_opts = %{relationships: opts[:relationships]}
-
case mastodon_type do
"mention" ->
put_status(response, activity, reading_user, render_opts)
@@ -111,6 +114,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
put_status(response, parent_activity_fn.(), reading_user, render_opts)
"move" ->
+ # Note: :skip_relationships option being applied to _account_ rendering (here)
put_target(response, activity, reading_user, render_opts)
"follow" ->
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index cea76e735..b5850e1ae 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -99,7 +99,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
true ->
actors = Enum.map(activities ++ parent_activities, &get_user(&1.data["actor"]))
- UserRelationship.view_relationships_option(reading_user, actors)
+ UserRelationship.view_relationships_option(reading_user, actors,
+ source_mutes_only: opts[:skip_relationships]
+ )
end
opts =
@@ -153,7 +155,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
AccountView.render("show.json", %{
user: user,
for: opts[:for],
- relationships: opts[:relationships]
+ relationships: opts[:relationships],
+ skip_relationships: opts[:skip_relationships]
}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
@@ -301,6 +304,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
_ -> []
end
+ # Status muted state (would do 1 request per status unless user mutes are preloaded)
muted =
thread_muted? ||
UserRelationship.exists?(
@@ -319,7 +323,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
AccountView.render("show.json", %{
user: user,
for: opts[:for],
- relationships: opts[:relationships]
+ relationships: opts[:relationships],
+ skip_relationships: opts[:skip_relationships]
}),
in_reply_to_id: reply_to && to_string(reply_to.id),
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
index dcba67d03..9d0b3b1e4 100644
--- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
+ only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2, skip_relationships?: 1]
alias Ecto.Changeset
alias Pleroma.Plugs.OAuthScopesPlug
@@ -139,7 +139,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
conn
|> add_link_headers(activities)
|> put_view(StatusView)
- |> render("index.json", activities: activities, for: for_user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: for_user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
@doc "POST /api/v1/pleroma/accounts/:id/subscribe"
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 dae7f0f2f..d4c5c5925 100644
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
alias Pleroma.Activity
alias Pleroma.Conversation.Participation
@@ -110,12 +110,11 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
end
def conversation_statuses(
- %{assigns: %{user: user}} = conn,
+ %{assigns: %{user: %{id: user_id} = user}} = conn,
%{"id" => participation_id} = params
) do
- with %Participation{} = participation <-
- Participation.get(participation_id, preload: [:conversation]),
- true <- user.id == participation.user_id do
+ with %Participation{user_id: ^user_id} = participation <-
+ Participation.get(participation_id, preload: [:conversation]) do
params =
params
|> Map.put("blocking_user", user)
@@ -124,13 +123,19 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
activities =
participation.conversation.ap_id
- |> ActivityPub.fetch_activities_for_context(params)
+ |> ActivityPub.fetch_activities_for_context_query(params)
+ |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
|> Enum.reverse()
conn
|> add_link_headers(activities)
|> put_view(StatusView)
- |> render("index.json", %{activities: activities, for: user, as: :activity})
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
else
_error ->
conn
@@ -184,13 +189,17 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
end
end
- def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
+ def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id} = params) do
with notifications <- Notification.set_read_up_to(user, max_id) do
notifications = Enum.take(notifications, 80)
conn
|> put_view(NotificationView)
- |> render("index.json", %{notifications: notifications, for: user})
+ |> render("index.json",
+ notifications: notifications,
+ for: user,
+ skip_relationships: skip_relationships?(params)
+ )
end
end
end
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index 0314535d2..9d3d7f978 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -64,5 +64,8 @@ defmodule Pleroma.Web.RichMedia.Helpers do
def fetch_data_for_activity(_), do: %{}
- def perform(:fetch, %Activity{} = activity), do: fetch_data_for_activity(activity)
+ def perform(:fetch, %Activity{} = activity) do
+ fetch_data_for_activity(activity)
+ :ok
+ end
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index ce69725dc..b10bf4466 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -361,9 +361,11 @@ defmodule Pleroma.Web.Router do
get("/notifications", NotificationController, :index)
get("/notifications/:id", NotificationController, :show)
+ post("/notifications/:id/dismiss", NotificationController, :dismiss)
post("/notifications/clear", NotificationController, :clear)
- post("/notifications/dismiss", NotificationController, :dismiss)
delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple)
+ # Deprecated: was removed in Mastodon v3, use `/notifications/:id/dismiss` instead
+ post("/notifications/dismiss", NotificationController, :dismiss)
get("/scheduled_statuses", ScheduledActivityController, :index)
get("/scheduled_statuses/:id", ScheduledActivityController, :show)