Credo.Check.Readability.PredicateFunctionNames

This check was recently improved in Credo and it does make sense for readability.

The offending functions in Pleroma have been renamed and a couple missing the ? suffix have been fixed as well.
This commit is contained in:
Mark Felder 2024-01-26 16:55:08 -05:00
parent 18d38486a5
commit 5b95abaeea
35 changed files with 150 additions and 150 deletions

View File

@ -57,7 +57,7 @@ def maybe_create_recipientships(participation, activity) do
3. Bump all relevant participations to 'unread' 3. Bump all relevant participations to 'unread'
""" """
def create_or_bump_for(activity, opts \\ []) do def create_or_bump_for(activity, opts \\ []) do
with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), with true <- Pleroma.Web.ActivityPub.Visibility.direct?(activity),
"Create" <- activity.data["type"], "Create" <- activity.data["type"],
%Object{} = object <- Object.normalize(activity, fetch: false), %Object{} = object <- Object.normalize(activity, fetch: false),
true <- object.data["type"] in ["Note", "Question"], true <- object.data["type"] in ["Note", "Question"],

View File

@ -138,23 +138,23 @@ defp update_emojis(emojis) do
emojis = emojis ++ regional_indicators emojis = emojis ++ regional_indicators
for emoji <- emojis do for emoji <- emojis do
def is_unicode_emoji?(unquote(emoji)), do: true def unicode?(unquote(emoji)), do: true
end end
def is_unicode_emoji?(_), do: false def unicode?(_), do: false
@emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/ @emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
def is_custom_emoji?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s) def custom?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
def is_custom_emoji?(_), do: false def custom?(_), do: false
def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":") def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":")
def maybe_strip_name(name), do: name def maybe_strip_name(name), do: name
def maybe_quote(name) when is_binary(name) do def maybe_quote(name) when is_binary(name) do
if is_unicode_emoji?(name) do if unicode?(name) do
name name
else else
if String.starts_with?(name, ":") do if String.starts_with?(name, ":") do

View File

@ -114,7 +114,7 @@ def response("/main/all") do
def response("/notices/" <> id) do def response("/notices/" <> id) do
with %Activity{} = activity <- Activity.get_by_id(id), with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.is_public?(activity) do true <- Visibility.public?(activity) do
activities = activities =
ActivityPub.fetch_activities_for_context(activity.data["context"]) ActivityPub.fetch_activities_for_context(activity.data["context"])
|> render_activities |> render_activities

View File

@ -2404,9 +2404,9 @@ defp put_password_hash(
defp put_password_hash(changeset), do: changeset defp put_password_hash(changeset), do: changeset
def is_internal_user?(%User{nickname: nil}), do: true def internal?(%User{nickname: nil}), do: true
def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true def internal?(%User{local: true, nickname: "internal." <> _}), do: true
def is_internal_user?(_), do: false def internal?(_), do: false
# A hack because user delete activities have a fake id for whatever reason # A hack because user delete activities have a fake id for whatever reason
# TODO: Get rid of this # TODO: Get rid of this

View File

@ -74,22 +74,22 @@ defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(
defp check_remote_limit(_), do: true defp check_remote_limit(_), do: true
def increase_note_count_if_public(actor, object) do def increase_note_count_if_public(actor, object) do
if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor} if public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
end end
def decrease_note_count_if_public(actor, object) do def decrease_note_count_if_public(actor, object) do
if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor} if public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
end end
def update_last_status_at_if_public(actor, object) do def update_last_status_at_if_public(actor, object) do
if is_public?(object), do: User.update_last_status_at(actor), else: {:ok, actor} if public?(object), do: User.update_last_status_at(actor), else: {:ok, actor}
end end
defp increase_replies_count_if_reply(%{ defp increase_replies_count_if_reply(%{
"object" => %{"inReplyTo" => reply_ap_id} = object, "object" => %{"inReplyTo" => reply_ap_id} = object,
"type" => "Create" "type" => "Create"
}) do }) do
if is_public?(object) do if public?(object) do
Object.increase_replies_count(reply_ap_id) Object.increase_replies_count(reply_ap_id)
end end
end end
@ -100,7 +100,7 @@ defp increase_quotes_count_if_quote(%{
"object" => %{"quoteUrl" => quote_ap_id} = object, "object" => %{"quoteUrl" => quote_ap_id} = object,
"type" => "Create" "type" => "Create"
}) do }) do
if is_public?(object) do if public?(object) do
Object.increase_quotes_count(quote_ap_id) Object.increase_quotes_count(quote_ap_id)
end end
end end

View File

@ -132,7 +132,7 @@ defp custom_emoji_react(object, data, emoji) do
def emoji_react(actor, object, emoji) do def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do with {:ok, data, meta} <- object_action(actor, object) do
data = data =
if Emoji.is_unicode_emoji?(emoji) do if Emoji.unicode?(emoji) do
unicode_emoji_react(object, data, emoji) unicode_emoji_react(object, data, emoji)
else else
custom_emoji_react(object, data, emoji) custom_emoji_react(object, data, emoji)
@ -348,7 +348,7 @@ def announce(actor, object, options \\ []) do
actor.ap_id == Relay.ap_id() -> actor.ap_id == Relay.ap_id() ->
[actor.follower_address] [actor.follower_address]
public? and Visibility.is_local_public?(object) -> public? and Visibility.local_public?(object) ->
[actor.follower_address, object.data["actor"], Utils.as_local_public()] [actor.follower_address, object.data["actor"], Utils.as_local_public()]
public? -> public? ->
@ -376,7 +376,7 @@ defp object_action(actor, object) do
# Address the actor of the object, and our actor's follower collection if the post is public. # Address the actor of the object, and our actor's follower collection if the post is public.
to = to =
if Visibility.is_public?(object) do if Visibility.public?(object) do
[actor.follower_address, object.data["actor"]] [actor.follower_address, object.data["actor"]]
else else
[object.data["actor"]] [object.data["actor"]]

View File

@ -10,9 +10,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
@impl true @impl true
def filter(%{"actor" => actor} = object) do def filter(%{"actor" => actor} = object) do
with true <- is_local?(actor), with true <- local?(actor),
true <- is_eligible_type?(object), true <- eligible_type?(object),
true <- is_note?(object), true <- note?(object),
false <- has_attachment?(object), false <- has_attachment?(object),
true <- only_mentions?(object) do true <- only_mentions?(object) do
{:reject, "[NoEmptyPolicy]"} {:reject, "[NoEmptyPolicy]"}
@ -24,7 +24,7 @@ def filter(%{"actor" => actor} = object) do
def filter(object), do: {:ok, object} def filter(object), do: {:ok, object}
defp is_local?(actor) do defp local?(actor) do
if actor |> String.starts_with?("#{Endpoint.url()}") do if actor |> String.starts_with?("#{Endpoint.url()}") do
true true
else else
@ -59,11 +59,11 @@ defp only_mentions?(%{"object" => %{"type" => "Note", "source" => source}}) do
defp only_mentions?(_), do: false defp only_mentions?(_), do: false
defp is_note?(%{"object" => %{"type" => "Note"}}), do: true defp note?(%{"object" => %{"type" => "Note"}}), do: true
defp is_note?(_), do: false defp note?(_), do: false
defp is_eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true defp eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true
defp is_eligible_type?(_), do: false defp eligible_type?(_), do: false
@impl true @impl true
def describe, do: {:ok, %{}} def describe, do: {:ok, %{}}

View File

@ -28,7 +28,7 @@ defp filter_object(%{"quoteUrl" => quote_url} = object) do
tags = object["tag"] || [] tags = object["tag"] || []
if Enum.any?(tags, fn tag -> if Enum.any?(tags, fn tag ->
CommonFixes.is_object_link_tag(tag) and tag["href"] == quote_url CommonFixes.object_link_tag?(tag) and tag["href"] == quote_url
end) do end) do
object object
else else

View File

@ -82,7 +82,7 @@ defp validate_announcable(cng) do
object when is_binary(object) <- get_field(cng, :object), object when is_binary(object) <- get_field(cng, :object),
%User{} = actor <- User.get_cached_by_ap_id(actor), %User{} = actor <- User.get_cached_by_ap_id(actor),
%Object{} = object <- Object.get_cached_by_ap_id(object), %Object{} = object <- Object.get_cached_by_ap_id(object),
false <- Visibility.is_public?(object) do false <- Visibility.public?(object) do
same_actor = object.data["actor"] == actor.ap_id same_actor = object.data["actor"] == actor.ap_id
recipients = get_field(cng, :to) ++ get_field(cng, :cc) recipients = get_field(cng, :to) ++ get_field(cng, :cc)
local_public = Utils.as_local_public() local_public = Utils.as_local_public()

View File

@ -99,7 +99,7 @@ def fix_quote_url(%{"_misskey_quote" => quote_url} = data) do
end end
def fix_quote_url(%{"tag" => [_ | _] = tags} = data) do def fix_quote_url(%{"tag" => [_ | _] = tags} = data) do
tag = Enum.find(tags, &is_object_link_tag/1) tag = Enum.find(tags, &object_link_tag?/1)
if not is_nil(tag) do if not is_nil(tag) do
data data
@ -112,7 +112,7 @@ def fix_quote_url(%{"tag" => [_ | _] = tags} = data) do
def fix_quote_url(data), do: data def fix_quote_url(data), do: data
# https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md # https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md
def is_object_link_tag(%{ def object_link_tag?(%{
"type" => "Link", "type" => "Link",
"mediaType" => media_type, "mediaType" => media_type,
"href" => href "href" => href
@ -121,5 +121,5 @@ def is_object_link_tag(%{
true true
end end
def is_object_link_tag(_), do: false def object_link_tag?(_), do: false
end end

View File

@ -74,10 +74,10 @@ defp fix_emoji_qualification(%{"content" => emoji} = data) do
new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji) new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji)
cond do cond do
Pleroma.Emoji.is_unicode_emoji?(emoji) -> Pleroma.Emoji.unicode?(emoji) ->
data data
Pleroma.Emoji.is_unicode_emoji?(new_emoji) -> Pleroma.Emoji.unicode?(new_emoji) ->
data |> Map.put("content", new_emoji) data |> Map.put("content", new_emoji)
true -> true ->
@ -90,7 +90,7 @@ defp fix_emoji_qualification(data), do: data
defp validate_emoji(cng) do defp validate_emoji(cng) do
content = get_field(cng, :content) content = get_field(cng, :content)
if Emoji.is_unicode_emoji?(content) || Emoji.is_custom_emoji?(content) do if Emoji.unicode?(content) || Emoji.custom?(content) do
cng cng
else else
cng cng
@ -101,7 +101,7 @@ defp validate_emoji(cng) do
defp maybe_validate_tag_presence(cng) do defp maybe_validate_tag_presence(cng) do
content = get_field(cng, :content) content = get_field(cng, :content)
if Emoji.is_unicode_emoji?(content) do if Emoji.unicode?(content) do
cng cng
else else
tag = get_field(cng, :tag) tag = get_field(cng, :tag)

View File

@ -62,7 +62,7 @@ defp maybe_federate(%Activity{} = activity, meta) do
with {:ok, local} <- Keyword.fetch(meta, :local) do with {:ok, local} <- Keyword.fetch(meta, :local) do
do_not_federate = meta[:do_not_federate] || !config().get([:instance, :federating]) do_not_federate = meta[:do_not_federate] || !config().get([:instance, :federating])
if !do_not_federate and local and not Visibility.is_local_public?(activity) do if !do_not_federate and local and not Visibility.local_public?(activity) do
activity = activity =
if object = Keyword.get(meta, :object_data) do if object = Keyword.get(meta, :object_data) do
%{activity | data: Map.put(activity.data, "object", object)} %{activity | data: Map.put(activity.data, "object", object)}

View File

@ -66,7 +66,7 @@ def remote_users(%User{id: user_id}, %{data: %{"to" => to} = data}) do
@doc """ @doc """
Determine if an activity can be represented by running it through Transmogrifier. Determine if an activity can be represented by running it through Transmogrifier.
""" """
def is_representable?(%Activity{} = activity) do def representable?(%Activity{} = activity) do
with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do
true true
else else
@ -246,7 +246,7 @@ def determine_inbox(
def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity) def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
when is_list(bcc) and bcc != [] do when is_list(bcc) and bcc != [] do
public = is_public?(activity) public = public?(activity)
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data) {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
[priority_recipients, recipients] = recipients(actor, activity) [priority_recipients, recipients] = recipients(actor, activity)
@ -291,7 +291,7 @@ def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
# Publishes an activity to all relevant peers. # Publishes an activity to all relevant peers.
def publish(%User{} = actor, %Activity{} = activity) do def publish(%User{} = actor, %Activity{} = activity) do
public = is_public?(activity) public = public?(activity)
if public && Config.get([:instance, :allow_relay]) do if public && Config.get([:instance, :allow_relay]) do
Logger.debug(fn -> "Relaying #{activity.data["id"]} out" end) Logger.debug(fn -> "Relaying #{activity.data["id"]} out" end)

View File

@ -58,7 +58,7 @@ defp fetch_target_user(ap_id, opts) do
@spec publish(any()) :: {:ok, Activity.t()} | {:error, any()} @spec publish(any()) :: {:ok, Activity.t()} | {:error, any()}
def publish(%Activity{data: %{"type" => "Create"}} = activity) do def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(), with %User{} = user <- get_actor(),
true <- Visibility.is_public?(activity) do true <- Visibility.public?(activity) do
CommonAPI.repeat(activity.id, user) CommonAPI.repeat(activity.id, user)
else else
error -> format_error(error) error -> format_error(error)

View File

@ -258,7 +258,7 @@ def handle(%{data: %{"type" => "Announce"}} = object, meta) do
Utils.add_announce_to_object(object, announced_object) Utils.add_announce_to_object(object, announced_object)
if !User.is_internal_user?(user) do if !User.internal?(user) do
Notification.create_notifications(object) Notification.create_notifications(object)
ap_streamer().stream_out(object) ap_streamer().stream_out(object)

View File

@ -783,7 +783,7 @@ def prepare_outgoing(%{"type" => "Announce", "actor" => ap_id, "object" => objec
|> Object.normalize(fetch: false) |> Object.normalize(fetch: false)
data = data =
if Visibility.is_private?(object) && object.data["actor"] == ap_id do if Visibility.private?(object) && object.data["actor"] == ap_id do
data |> Map.put("object", object |> Map.get(:data) |> prepare_object) data |> Map.put("object", object |> Map.get(:data) |> prepare_object)
else else
data |> maybe_fix_object_url data |> maybe_fix_object_url

View File

@ -167,7 +167,7 @@ def maybe_federate(%Activity{local: true, data: %{"type" => type}} = activity) d
with true <- Config.get!([:instance, :federating]), with true <- Config.get!([:instance, :federating]),
true <- type != "Block" || outgoing_blocks, true <- type != "Block" || outgoing_blocks,
false <- Visibility.is_local_public?(activity) do false <- Visibility.local_public?(activity) do
Pleroma.Web.Federator.publish(activity) Pleroma.Web.Federator.publish(activity)
end end
@ -277,7 +277,7 @@ def make_like_data(
object_actor = User.get_cached_by_ap_id(object_actor_id) object_actor = User.get_cached_by_ap_id(object_actor_id)
to = to =
if Visibility.is_public?(object) do if Visibility.public?(object) do
[actor.follower_address, object.data["actor"]] [actor.follower_address, object.data["actor"]]
else else
[object.data["actor"]] [object.data["actor"]]

View File

@ -11,28 +11,28 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
require Pleroma.Constants require Pleroma.Constants
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean() @spec public?(Object.t() | Activity.t() | map()) :: boolean()
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false def public?(%Object{data: %{"type" => "Tombstone"}}), do: false
def is_public?(%Object{data: data}), do: is_public?(data) def public?(%Object{data: data}), do: public?(data)
def is_public?(%Activity{data: %{"type" => "Move"}}), do: true def public?(%Activity{data: %{"type" => "Move"}}), do: true
def is_public?(%Activity{data: data}), do: is_public?(data) def public?(%Activity{data: data}), do: public?(data)
def is_public?(%{"directMessage" => true}), do: false def public?(%{"directMessage" => true}), do: false
def is_public?(data) do def public?(data) do
Utils.label_in_message?(Pleroma.Constants.as_public(), data) or Utils.label_in_message?(Pleroma.Constants.as_public(), data) or
Utils.label_in_message?(Utils.as_local_public(), data) Utils.label_in_message?(Utils.as_local_public(), data)
end end
def is_local_public?(%Object{data: data}), do: is_local_public?(data) def local_public?(%Object{data: data}), do: local_public?(data)
def is_local_public?(%Activity{data: data}), do: is_local_public?(data) def local_public?(%Activity{data: data}), do: local_public?(data)
def is_local_public?(data) do def local_public?(data) do
Utils.label_in_message?(Utils.as_local_public(), data) and Utils.label_in_message?(Utils.as_local_public(), data) and
not Utils.label_in_message?(Pleroma.Constants.as_public(), data) not Utils.label_in_message?(Pleroma.Constants.as_public(), data)
end end
def is_private?(activity) do def private?(activity) do
with false <- is_public?(activity), with false <- public?(activity),
%User{follower_address: follower_address} <- %User{follower_address: follower_address} <-
User.get_cached_by_ap_id(activity.data["actor"]) do User.get_cached_by_ap_id(activity.data["actor"]) do
follower_address in activity.data["to"] follower_address in activity.data["to"]
@ -41,20 +41,20 @@ def is_private?(activity) do
end end
end end
def is_announceable?(activity, user, public \\ true) do def announceable?(activity, user, public \\ true) do
is_public?(activity) || public?(activity) ||
(!public && is_private?(activity) && activity.data["actor"] == user.ap_id) (!public && private?(activity) && activity.data["actor"] == user.ap_id)
end end
def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true def direct?(%Activity{data: %{"directMessage" => true}}), do: true
def is_direct?(%Object{data: %{"directMessage" => true}}), do: true def direct?(%Object{data: %{"directMessage" => true}}), do: true
def is_direct?(activity) do def direct?(activity) do
!is_public?(activity) && !is_private?(activity) !public?(activity) && !private?(activity)
end end
def is_list?(%{data: %{"listMessage" => _}}), do: true def list?(%{data: %{"listMessage" => _}}), do: true
def is_list?(_), do: false def list?(_), do: false
@spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean() @spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean()
def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false
@ -77,7 +77,7 @@ def visible_for_user?(%{__struct__: module} = message, nil)
when module in [Activity, Object] do when module in [Activity, Object] do
if restrict_unauthenticated_access?(message), if restrict_unauthenticated_access?(message),
do: false, do: false,
else: is_public?(message) and not is_local_public?(message) else: public?(message) and not local_public?(message)
end end
def visible_for_user?(%{__struct__: module} = message, user) def visible_for_user?(%{__struct__: module} = message, user)
@ -86,8 +86,8 @@ def visible_for_user?(%{__struct__: module} = message, user)
y = [message.data["actor"]] ++ message.data["to"] ++ (message.data["cc"] || []) y = [message.data["actor"]] ++ message.data["to"] ++ (message.data["cc"] || [])
user_is_local = user.local user_is_local = user.local
federatable = not is_local_public?(message) federatable = not local_public?(message)
(is_public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable) (public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable)
end end
def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do

View File

@ -372,7 +372,7 @@ def public_announce?(_, %{visibility: visibility})
do: visibility in ~w(public unlisted) do: visibility in ~w(public unlisted)
def public_announce?(object, _) do def public_announce?(object, _) do
Visibility.is_public?(object) Visibility.public?(object)
end end
def get_visibility(_, _, %Participation{}), do: {"direct", "direct"} def get_visibility(_, _, %Participation{}), do: {"direct", "direct"}
@ -500,7 +500,7 @@ defp object_type_is_allowed_for_pin(%{data: %{"type" => type}}) do
end end
defp activity_is_public(activity) do defp activity_is_public(activity) do
with false <- Visibility.is_public?(activity) do with false <- Visibility.public?(activity) do
{:error, :visibility_error} {:error, :visibility_error}
end end
end end

View File

@ -109,7 +109,7 @@ def get_to_and_cc(%{visibility: "private"} = draft) do
def get_to_and_cc(%{visibility: "direct"} = draft) do def get_to_and_cc(%{visibility: "direct"} = draft) do
# If the OP is a DM already, add the implicit actor. # If the OP is a DM already, add the implicit actor.
if draft.in_reply_to && Visibility.is_direct?(draft.in_reply_to) do if draft.in_reply_to && Visibility.direct?(draft.in_reply_to) do
{Enum.uniq([draft.in_reply_to.data["actor"] | draft.mentions]), []} {Enum.uniq([draft.in_reply_to.data["actor"] | draft.mentions]), []}
else else
{draft.mentions, []} {draft.mentions, []}

View File

@ -16,7 +16,7 @@ defmodule Pleroma.Web.EmbedController do
def show(conn, %{"id" => id}) do def show(conn, %{"id" => id}) do
with %Activity{local: true} = activity <- with %Activity{local: true} = activity <-
Activity.get_by_id_with_object(id), Activity.get_by_id_with_object(id),
true <- Visibility.is_public?(activity.object) do true <- Visibility.public?(activity.object) do
{:ok, author} = User.get_or_fetch(activity.object.data["actor"]) {:ok, author} = User.get_or_fetch(activity.object.data["actor"])
conn conn

View File

@ -85,12 +85,12 @@ def get_locales do
Process.get({Pleroma.Web.Gettext, :locales}, []) Process.get({Pleroma.Web.Gettext, :locales}, [])
end end
def is_locale_list(locales) do def locale_list?(locales) do
Enum.all?(locales, &is_binary/1) Enum.all?(locales, &is_binary/1)
end end
def put_locales(locales) do def put_locales(locales) do
if is_locale_list(locales) do if locale_list?(locales) do
Process.put({Pleroma.Web.Gettext, :locales}, Enum.uniq(locales)) Process.put({Pleroma.Web.Gettext, :locales}, Enum.uniq(locales))
Gettext.put_locale(Enum.at(locales, 0, Gettext.get_locale())) Gettext.put_locale(Enum.at(locales, 0, Gettext.get_locale()))
:ok :ok

View File

@ -214,7 +214,7 @@ defp do_render("show.json", %{user: user} = opts) do
do: user.follower_count, do: user.follower_count,
else: 0 else: 0
bot = is_bot?(user) bot = bot?(user)
emojis = emojis =
Enum.map(user.emoji, fn {shortcode, raw_url} -> Enum.map(user.emoji, fn {shortcode, raw_url} ->
@ -471,7 +471,7 @@ defp maybe_show_birthday(data, _, _) do
defp image_url(%{"url" => [%{"href" => href} | _]}), do: href defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
defp image_url(_), do: nil defp image_url(_), do: nil
defp is_bot?(user) do defp bot?(user) do
# Because older and/or Mastodon clients may not recognize a Group actor properly, # Because older and/or Mastodon clients may not recognize a Group actor properly,
# and currently the group actor can only boost things, we should let these clients # and currently the group actor can only boost things, we should let these clients
# think groups are bots. # think groups are bots.

View File

@ -138,9 +138,9 @@ def get_user_tokens(%User{id: user_id}) do
|> Repo.all() |> Repo.all()
end end
def is_expired?(%__MODULE__{valid_until: valid_until}) do def expired?(%__MODULE__{valid_until: valid_until}) do
NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) > 0 NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) > 0
end end
def is_expired?(_), do: false def expired?(_), do: false
end end

View File

@ -37,7 +37,7 @@ def object(conn, _params) do
with id <- Endpoint.url() <> conn.request_path, with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {_, %Activity{} = activity} <-
{:activity, Activity.get_create_by_object_ap_id_with_object(id)}, {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.public?(activity)} do
redirect(conn, to: "/notice/#{activity.id}") redirect(conn, to: "/notice/#{activity.id}")
else else
reason when reason in [{:public?, false}, {:activity, nil}] -> reason when reason in [{:public?, false}, {:activity, nil}] ->
@ -56,7 +56,7 @@ def activity(%{assigns: %{format: format}} = conn, _params)
def activity(conn, _params) do def activity(conn, _params) do
with id <- Endpoint.url() <> conn.request_path, with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.public?(activity)} do
redirect(conn, to: "/notice/#{activity.id}") redirect(conn, to: "/notice/#{activity.id}")
else else
reason when reason in [{:public?, false}, {:activity, nil}] -> reason when reason in [{:public?, false}, {:activity, nil}] ->
@ -69,7 +69,7 @@ def activity(conn, _params) do
def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)}, {_, true} <- {:public?, Visibility.public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
cond do cond do
format in ["json", "activity+json"] -> format in ["json", "activity+json"] ->
@ -106,7 +106,7 @@ def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
# Returns an HTML embedded <audio> or <video> player suitable for embed iframes. # Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
def notice_player(conn, %{"id" => id}) do def notice_player(conn, %{"id" => id}) do
with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id), with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.is_public?(activity), true <- Visibility.public?(activity),
{_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)}, {_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)},
%Object{} = object <- Object.normalize(activity, fetch: false), %Object{} = object <- Object.normalize(activity, fetch: false),
%{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object, %{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,

View File

@ -23,14 +23,14 @@ def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
def call(conn, _) do def call(conn, _) do
with {:ok, token_str} <- fetch_token_str(conn) do with {:ok, token_str} <- fetch_token_str(conn) do
with {:ok, user, user_token} <- fetch_user_and_token(token_str), with {:ok, user, user_token} <- fetch_user_and_token(token_str),
false <- Token.is_expired?(user_token) do false <- Token.expired?(user_token) do
conn conn
|> assign(:token, user_token) |> assign(:token, user_token)
|> assign(:user, user) |> assign(:user, user)
else else
_ -> _ ->
with {:ok, app, app_token} <- fetch_app_and_token(token_str), with {:ok, app, app_token} <- fetch_app_and_token(token_str),
false <- Token.is_expired?(app_token) do false <- Token.expired?(app_token) do
conn conn
|> assign(:token, app_token) |> assign(:token, app_token)
|> assign(:app, app) |> assign(:app, app)

View File

@ -9,7 +9,7 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
def ttl(data, _url) do def ttl(data, _url) do
image = Map.get(data, :image) image = Map.get(data, :image)
if is_aws_signed_url(image) do if aws_signed_url?(image) do
image image
|> parse_query_params() |> parse_query_params()
|> format_query_params() |> format_query_params()
@ -19,13 +19,13 @@ def ttl(data, _url) do
end end
end end
defp is_aws_signed_url(image) when is_binary(image) and image != "" do defp aws_signed_url?(image) when is_binary(image) and image != "" do
%URI{host: host, query: query} = URI.parse(image) %URI{host: host, query: query} = URI.parse(image)
String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires") String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires")
end end
defp is_aws_signed_url(_), do: nil defp aws_signed_url?(_), do: nil
defp parse_query_params(image) do defp parse_query_params(image) do
%URI{query: query} = URI.parse(image) %URI{query: query} = URI.parse(image)

View File

@ -22,7 +22,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do
with %Activity{local: true} = activity <- with %Activity{local: true} = activity <-
Activity.get_by_id_with_object(notice_id), Activity.get_by_id_with_object(notice_id),
true <- Visibility.is_public?(activity.object), true <- Visibility.public?(activity.object),
{_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)}, {_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)},
%User{} = user <- User.get_by_ap_id(activity.object.data["actor"]) do %User{} = user <- User.get_by_ap_id(activity.object.data["actor"]) do
url = Helpers.url(conn) <> conn.request_path url = Helpers.url(conn) <> conn.request_path

View File

@ -245,7 +245,7 @@ defp do_stream("participation", participation) do
defp do_stream("list", item) do defp do_stream("list", item) do
# filter the recipient list if the activity is not public, see #270. # filter the recipient list if the activity is not public, see #270.
recipient_lists = recipient_lists =
case Visibility.is_public?(item) do case Visibility.public?(item) do
true -> true ->
Pleroma.List.get_lists_from_activity(item) Pleroma.List.get_lists_from_activity(item)

View File

@ -29,7 +29,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
# GET /ostatus_subscribe # GET /ostatus_subscribe
# #
def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
case is_status?(acct) do case status?(acct) do
true -> follow_status(conn, user, acct) true -> follow_status(conn, user, acct)
_ -> follow_account(conn, user, acct) _ -> follow_account(conn, user, acct)
end end
@ -57,7 +57,7 @@ defp follow_account(conn, user, acct) do
defp follow_template(%User{} = _user), do: "follow.html" defp follow_template(%User{} = _user), do: "follow.html"
defp follow_template(_), do: "follow_login.html" defp follow_template(_), do: "follow_login.html"
defp is_status?(acct) do defp status?(acct) do
case Fetcher.fetch_and_contain_remote_object_from_id(acct) do case Fetcher.fetch_and_contain_remote_object_from_id(acct) do
{:ok, %{"type" => type}} when type in @status_types -> {:ok, %{"type" => type}} when type in @status_types ->
true true

View File

@ -6,26 +6,26 @@ defmodule Pleroma.EmojiTest do
use ExUnit.Case, async: true use ExUnit.Case, async: true
alias Pleroma.Emoji alias Pleroma.Emoji
describe "is_unicode_emoji?/1" do describe "unicode?/1" do
test "tells if a string is an unicode emoji" do test "tells if a string is an unicode emoji" do
refute Emoji.is_unicode_emoji?("X") refute Emoji.unicode?("X")
refute Emoji.is_unicode_emoji?("") refute Emoji.unicode?("")
# Only accept fully-qualified (RGI) emoji # Only accept fully-qualified (RGI) emoji
# See http://www.unicode.org/reports/tr51/ # See http://www.unicode.org/reports/tr51/
refute Emoji.is_unicode_emoji?("") refute Emoji.unicode?("")
refute Emoji.is_unicode_emoji?("") refute Emoji.unicode?("")
assert Emoji.is_unicode_emoji?("🥺") assert Emoji.unicode?("🥺")
assert Emoji.is_unicode_emoji?("🤰") assert Emoji.unicode?("🤰")
assert Emoji.is_unicode_emoji?("❤️") assert Emoji.unicode?("❤️")
assert Emoji.is_unicode_emoji?("🏳️‍⚧️") assert Emoji.unicode?("🏳️‍⚧️")
assert Emoji.is_unicode_emoji?("🫵") assert Emoji.unicode?("🫵")
# Additionally, we accept regional indicators. # Additionally, we accept regional indicators.
assert Emoji.is_unicode_emoji?("🇵") assert Emoji.unicode?("🇵")
assert Emoji.is_unicode_emoji?("🇴") assert Emoji.unicode?("🇴")
assert Emoji.is_unicode_emoji?("🇬") assert Emoji.unicode?("🇬")
end end
end end

View File

@ -2424,20 +2424,20 @@ test "external_users/1 external active users with limit", %{user1: user1, user2:
end end
end end
describe "is_internal_user?/1" do describe "internal?/1" do
test "non-internal user returns false" do test "non-internal user returns false" do
user = insert(:user) user = insert(:user)
refute User.is_internal_user?(user) refute User.internal?(user)
end end
test "user with no nickname returns true" do test "user with no nickname returns true" do
user = insert(:user, %{nickname: nil}) user = insert(:user, %{nickname: nil})
assert User.is_internal_user?(user) assert User.internal?(user)
end end
test "user with internal-prefixed nickname returns true" do test "user with internal-prefixed nickname returns true" do
user = insert(:user, %{nickname: "internal.test"}) user = insert(:user, %{nickname: "internal.test"})
assert User.is_internal_user?(user) assert User.internal?(user)
end end
end end

View File

@ -221,7 +221,7 @@ test "it doesn't return a local-only object", %{conn: conn} do
user = insert(:user) user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
object = Object.normalize(post, fetch: false) object = Object.normalize(post, fetch: false)
uuid = String.split(object.data["id"], "/") |> List.last() uuid = String.split(object.data["id"], "/") |> List.last()
@ -238,7 +238,7 @@ test "returns local-only objects when authenticated", %{conn: conn} do
user = insert(:user) user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
object = Object.normalize(post, fetch: false) object = Object.normalize(post, fetch: false)
uuid = String.split(object.data["id"], "/") |> List.last() uuid = String.split(object.data["id"], "/") |> List.last()
@ -259,7 +259,7 @@ test "does not return local-only objects for remote users", %{conn: conn} do
{:ok, post} = {:ok, post} =
CommonAPI.post(user, %{status: "test @#{reader.nickname}", visibility: "local"}) CommonAPI.post(user, %{status: "test @#{reader.nickname}", visibility: "local"})
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
object = Object.normalize(post, fetch: false) object = Object.normalize(post, fetch: false)
uuid = String.split(object.data["id"], "/") |> List.last() uuid = String.split(object.data["id"], "/") |> List.last()
@ -436,7 +436,7 @@ test "it doesn't return a local-only activity", %{conn: conn} do
user = insert(:user) user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
uuid = String.split(post.data["id"], "/") |> List.last() uuid = String.split(post.data["id"], "/") |> List.last()
@ -452,7 +452,7 @@ test "returns local-only activities when authenticated", %{conn: conn} do
user = insert(:user) user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) assert Pleroma.Web.ActivityPub.Visibility.local_public?(post)
uuid = String.split(post.data["id"], "/") |> List.last() uuid = String.split(post.data["id"], "/") |> List.last()

View File

@ -52,60 +52,60 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
} }
end end
test "is_direct?", %{ test "direct?", %{
public: public, public: public,
private: private, private: private,
direct: direct, direct: direct,
unlisted: unlisted, unlisted: unlisted,
list: list list: list
} do } do
assert Visibility.is_direct?(direct) assert Visibility.direct?(direct)
refute Visibility.is_direct?(public) refute Visibility.direct?(public)
refute Visibility.is_direct?(private) refute Visibility.direct?(private)
refute Visibility.is_direct?(unlisted) refute Visibility.direct?(unlisted)
assert Visibility.is_direct?(list) assert Visibility.direct?(list)
end end
test "is_public?", %{ test "public?", %{
public: public, public: public,
private: private, private: private,
direct: direct, direct: direct,
unlisted: unlisted, unlisted: unlisted,
list: list list: list
} do } do
refute Visibility.is_public?(direct) refute Visibility.public?(direct)
assert Visibility.is_public?(public) assert Visibility.public?(public)
refute Visibility.is_public?(private) refute Visibility.public?(private)
assert Visibility.is_public?(unlisted) assert Visibility.public?(unlisted)
refute Visibility.is_public?(list) refute Visibility.public?(list)
end end
test "is_private?", %{ test "private?", %{
public: public, public: public,
private: private, private: private,
direct: direct, direct: direct,
unlisted: unlisted, unlisted: unlisted,
list: list list: list
} do } do
refute Visibility.is_private?(direct) refute Visibility.private?(direct)
refute Visibility.is_private?(public) refute Visibility.private?(public)
assert Visibility.is_private?(private) assert Visibility.private?(private)
refute Visibility.is_private?(unlisted) refute Visibility.private?(unlisted)
refute Visibility.is_private?(list) refute Visibility.private?(list)
end end
test "is_list?", %{ test "list?", %{
public: public, public: public,
private: private, private: private,
direct: direct, direct: direct,
unlisted: unlisted, unlisted: unlisted,
list: list list: list
} do } do
refute Visibility.is_list?(direct) refute Visibility.list?(direct)
refute Visibility.is_list?(public) refute Visibility.list?(public)
refute Visibility.is_list?(private) refute Visibility.list?(private)
refute Visibility.is_list?(unlisted) refute Visibility.list?(unlisted)
assert Visibility.is_list?(list) assert Visibility.list?(list)
end end
test "visible_for_user? Activity", %{ test "visible_for_user? Activity", %{
@ -227,7 +227,7 @@ test "doesn't die when the user doesn't exist",
} do } do
Repo.delete(user) Repo.delete(user)
Pleroma.User.invalidate_cache(user) Pleroma.User.invalidate_cache(user)
refute Visibility.is_private?(direct) refute Visibility.private?(direct)
end end
test "get_visibility", %{ test "get_visibility", %{

View File

@ -506,7 +506,7 @@ test "when replying to a conversation / participation, it will set the correct c
{:ok, convo_reply} = {:ok, convo_reply} =
CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id}) CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id})
assert Visibility.is_direct?(convo_reply) assert Visibility.direct?(convo_reply)
assert activity.data["context"] == convo_reply.data["context"] assert activity.data["context"] == convo_reply.data["context"]
end end
@ -924,7 +924,7 @@ test "repeating a status" do
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user) {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
assert Visibility.is_public?(announce_activity) assert Visibility.public?(announce_activity)
end end
test "can't repeat a repeat" do test "can't repeat a repeat" do
@ -946,7 +946,7 @@ test "repeating a status privately" do
{:ok, %Activity{} = announce_activity} = {:ok, %Activity{} = announce_activity} =
CommonAPI.repeat(activity.id, user, %{visibility: "private"}) CommonAPI.repeat(activity.id, user, %{visibility: "private"})
assert Visibility.is_private?(announce_activity) assert Visibility.private?(announce_activity)
refute Visibility.visible_for_user?(announce_activity, nil) refute Visibility.visible_for_user?(announce_activity, nil)
end end
@ -959,7 +959,7 @@ test "author can repeat own private statuses" do
{:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, author) {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, author)
assert Visibility.is_private?(announce_activity) assert Visibility.private?(announce_activity)
refute Visibility.visible_for_user?(announce_activity, nil) refute Visibility.visible_for_user?(announce_activity, nil)
assert Visibility.visible_for_user?(activity, follower) assert Visibility.visible_for_user?(activity, follower)
@ -1604,7 +1604,7 @@ test "post" do
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
{:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"}) {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
assert_not_called(Pleroma.Web.Federator.publish(activity)) assert_not_called(Pleroma.Web.Federator.publish(activity))
end end
end end
@ -1619,7 +1619,7 @@ test "delete" do
assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} = assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} =
CommonAPI.delete(activity_id, user) CommonAPI.delete(activity_id, user)
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
assert_not_called(Pleroma.Web.Federator.publish(activity)) assert_not_called(Pleroma.Web.Federator.publish(activity))
end end
end end
@ -1635,7 +1635,7 @@ test "repeat" do
assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} = assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} =
CommonAPI.repeat(activity_id, user) CommonAPI.repeat(activity_id, user)
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end
@ -1653,7 +1653,7 @@ test "unrepeat" do
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} = assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
CommonAPI.unrepeat(activity_id, user) CommonAPI.unrepeat(activity_id, user)
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end
@ -1668,7 +1668,7 @@ test "favorite" do
assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} = assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} =
CommonAPI.favorite(user, activity.id) CommonAPI.favorite(user, activity.id)
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end
@ -1683,7 +1683,7 @@ test "unfavorite" do
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user) assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user)
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end
@ -1697,7 +1697,7 @@ test "react_with_emoji" do
assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} = assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} =
CommonAPI.react_with_emoji(activity.id, user, "👍") CommonAPI.react_with_emoji(activity.id, user, "👍")
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end
@ -1713,7 +1713,7 @@ test "unreact_with_emoji" do
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} = assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
CommonAPI.unreact_with_emoji(activity.id, user, "👍") CommonAPI.unreact_with_emoji(activity.id, user, "👍")
assert Visibility.is_local_public?(activity) assert Visibility.local_public?(activity)
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end