Merge remote-tracking branch 'remotes/upstream/develop' into 1335-user-api-id-fields-relations
# Conflicts: # mix.lock
This commit is contained in:
commit
52cc7de82c
|
@ -31,6 +31,7 @@ build:
|
||||||
|
|
||||||
benchmark:
|
benchmark:
|
||||||
stage: benchmark
|
stage: benchmark
|
||||||
|
when: manual
|
||||||
variables:
|
variables:
|
||||||
MIX_ENV: benchmark
|
MIX_ENV: benchmark
|
||||||
services:
|
services:
|
||||||
|
@ -55,6 +56,19 @@ unit-testing:
|
||||||
- mix ecto.migrate
|
- mix ecto.migrate
|
||||||
- mix coveralls --preload-modules
|
- mix coveralls --preload-modules
|
||||||
|
|
||||||
|
federated-testing:
|
||||||
|
stage: test
|
||||||
|
services:
|
||||||
|
- name: minibikini/postgres-with-rum:12
|
||||||
|
alias: postgres
|
||||||
|
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||||
|
script:
|
||||||
|
- mix deps.get
|
||||||
|
- mix ecto.create
|
||||||
|
- mix ecto.migrate
|
||||||
|
- epmd -daemon
|
||||||
|
- mix test --trace --only federated
|
||||||
|
|
||||||
unit-testing-rum:
|
unit-testing-rum:
|
||||||
stage: test
|
stage: test
|
||||||
services:
|
services:
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
# Do not print debug messages in production
|
# Do not print debug messages in production
|
||||||
config :logger, :console, level: :warn
|
config :logger, :console, level: :warn
|
||||||
|
config :logger, :ex_syslogger, level: :warn
|
||||||
|
|
||||||
# ## SSL Support
|
# ## SSL Support
|
||||||
#
|
#
|
||||||
|
|
|
@ -303,4 +303,17 @@ def restrict_deactivated_users(query) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search
|
defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search
|
||||||
|
|
||||||
|
def direct_conversation_id(activity, for_user) do
|
||||||
|
alias Pleroma.Conversation.Participation
|
||||||
|
|
||||||
|
with %{data: %{"context" => context}} when is_binary(context) <- activity,
|
||||||
|
%Pleroma.Conversation{} = conversation <- Pleroma.Conversation.get_for_ap_id(context),
|
||||||
|
%Participation{id: participation_id} <-
|
||||||
|
Participation.for_user_and_conversation(for_user, conversation) do
|
||||||
|
participation_id
|
||||||
|
else
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -272,20 +272,6 @@ def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers"
|
||||||
def ap_following(%User{following_address: fa}) when is_binary(fa), do: fa
|
def ap_following(%User{following_address: fa}) when is_binary(fa), do: fa
|
||||||
def ap_following(%User{} = user), do: "#{ap_id(user)}/following"
|
def ap_following(%User{} = user), do: "#{ap_id(user)}/following"
|
||||||
|
|
||||||
def user_info(%User{} = user, args \\ %{}) do
|
|
||||||
following_count = Map.get(args, :following_count, user.following_count)
|
|
||||||
follower_count = Map.get(args, :follower_count, user.follower_count)
|
|
||||||
|
|
||||||
%{
|
|
||||||
note_count: user.note_count,
|
|
||||||
locked: user.locked,
|
|
||||||
confirmation_pending: user.confirmation_pending,
|
|
||||||
default_scope: user.default_scope,
|
|
||||||
follower_count: follower_count,
|
|
||||||
following_count: following_count
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def follow_state(%User{} = user, %User{} = target) do
|
def follow_state(%User{} = user, %User{} = target) do
|
||||||
case Utils.fetch_latest_follow(user, target) do
|
case Utils.fetch_latest_follow(user, target) do
|
||||||
%{data: %{"state" => state}} -> state
|
%{data: %{"state" => state}} -> state
|
||||||
|
@ -304,10 +290,6 @@ def set_follow_state_cache(user_ap_id, target_ap_id, state) do
|
||||||
Cachex.put(:user_cache, "follow_state:#{user_ap_id}|#{target_ap_id}", state)
|
Cachex.put(:user_cache, "follow_state:#{user_ap_id}|#{target_ap_id}", state)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_info_cache(user, args) do
|
|
||||||
Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user, args))
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec restrict_deactivated(Ecto.Query.t()) :: Ecto.Query.t()
|
@spec restrict_deactivated(Ecto.Query.t()) :: Ecto.Query.t()
|
||||||
def restrict_deactivated(query) do
|
def restrict_deactivated(query) do
|
||||||
from(u in query, where: u.deactivated != ^true)
|
from(u in query, where: u.deactivated != ^true)
|
||||||
|
@ -709,7 +691,6 @@ def set_cache({:error, err}), do: {:error, err}
|
||||||
def set_cache(%User{} = user) do
|
def set_cache(%User{} = user) do
|
||||||
Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
|
Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
|
||||||
Cachex.put(:user_cache, "nickname:#{user.nickname}", user)
|
Cachex.put(:user_cache, "nickname:#{user.nickname}", user)
|
||||||
Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user))
|
|
||||||
{:ok, user}
|
{:ok, user}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -728,7 +709,6 @@ def update_and_set_cache(changeset) do
|
||||||
def invalidate_cache(user) do
|
def invalidate_cache(user) do
|
||||||
Cachex.del(:user_cache, "ap_id:#{user.ap_id}")
|
Cachex.del(:user_cache, "ap_id:#{user.ap_id}")
|
||||||
Cachex.del(:user_cache, "nickname:#{user.nickname}")
|
Cachex.del(:user_cache, "nickname:#{user.nickname}")
|
||||||
Cachex.del(:user_cache, "user_info:#{user.id}")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_cached_by_ap_id(ap_id) do
|
def get_cached_by_ap_id(ap_id) do
|
||||||
|
@ -796,11 +776,6 @@ def get_by_nickname_or_email(nickname_or_email) do
|
||||||
get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email)
|
get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_cached_user_info(user) do
|
|
||||||
key = "user_info:#{user.id}"
|
|
||||||
Cachex.fetch!(:user_cache, key, fn -> user_info(user) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_by_nickname(nickname), do: ActivityPub.make_user_from_nickname(nickname)
|
def fetch_by_nickname(nickname), do: ActivityPub.make_user_from_nickname(nickname)
|
||||||
|
|
||||||
def get_or_fetch_by_nickname(nickname) do
|
def get_or_fetch_by_nickname(nickname) do
|
||||||
|
|
|
@ -71,18 +71,17 @@ defp do_render("show.json", %{user: user} = opts) do
|
||||||
|
|
||||||
image = User.avatar_url(user) |> MediaProxy.url()
|
image = User.avatar_url(user) |> MediaProxy.url()
|
||||||
header = User.banner_url(user) |> MediaProxy.url()
|
header = User.banner_url(user) |> MediaProxy.url()
|
||||||
user_info = User.get_cached_user_info(user)
|
|
||||||
|
|
||||||
following_count =
|
following_count =
|
||||||
if !user.hide_follows_count or !user.hide_follows or opts[:for] == user do
|
if !user.hide_follows_count or !user.hide_follows or opts[:for] == user do
|
||||||
user_info.following_count
|
user.following_count || 0
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
followers_count =
|
followers_count =
|
||||||
if !user.hide_followers_count or !user.hide_followers or opts[:for] == user do
|
if !user.hide_followers_count or !user.hide_followers or opts[:for] == user do
|
||||||
user_info.follower_count
|
user.follower_count || 0
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
@ -144,7 +143,7 @@ defp do_render("show.json", %{user: user} = opts) do
|
||||||
|
|
||||||
# Pleroma extension
|
# Pleroma extension
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
confirmation_pending: user_info.confirmation_pending,
|
confirmation_pending: user.confirmation_pending,
|
||||||
tags: user.tags,
|
tags: user.tags,
|
||||||
hide_followers_count: user.hide_followers_count,
|
hide_followers_count: user.hide_followers_count,
|
||||||
hide_follows_count: user.hide_follows_count,
|
hide_follows_count: user.hide_follows_count,
|
||||||
|
@ -157,7 +156,7 @@ defp do_render("show.json", %{user: user} = opts) do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> maybe_put_role(user, opts[:for])
|
|> maybe_put_role(user, opts[:for])
|
||||||
|> maybe_put_settings(user, opts[:for], user_info)
|
|> maybe_put_settings(user, opts[:for], opts)
|
||||||
|> maybe_put_notification_settings(user, opts[:for])
|
|> maybe_put_notification_settings(user, opts[:for])
|
||||||
|> maybe_put_settings_store(user, opts[:for], opts)
|
|> maybe_put_settings_store(user, opts[:for], opts)
|
||||||
|> maybe_put_chat_token(user, opts[:for], opts)
|
|> maybe_put_chat_token(user, opts[:for], opts)
|
||||||
|
@ -191,7 +190,7 @@ defp maybe_put_settings(
|
||||||
data,
|
data,
|
||||||
%User{id: user_id} = user,
|
%User{id: user_id} = user,
|
||||||
%User{id: user_id},
|
%User{id: user_id},
|
||||||
_user_info
|
_opts
|
||||||
) do
|
) do
|
||||||
data
|
data
|
||||||
|> Kernel.put_in([:source, :privacy], user.default_scope)
|
|> Kernel.put_in([:source, :privacy], user.default_scope)
|
||||||
|
|
|
@ -9,8 +9,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.ActivityExpiration
|
alias Pleroma.ActivityExpiration
|
||||||
alias Pleroma.Conversation
|
|
||||||
alias Pleroma.Conversation.Participation
|
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
@ -245,12 +243,8 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
||||||
direct_conversation_id =
|
direct_conversation_id =
|
||||||
with {_, nil} <- {:direct_conversation_id, opts[:direct_conversation_id]},
|
with {_, nil} <- {:direct_conversation_id, opts[:direct_conversation_id]},
|
||||||
{_, true} <- {:include_id, opts[:with_direct_conversation_id]},
|
{_, true} <- {:include_id, opts[:with_direct_conversation_id]},
|
||||||
{_, %User{} = for_user} <- {:for_user, opts[:for]},
|
{_, %User{} = for_user} <- {:for_user, opts[:for]} do
|
||||||
%{data: %{"context" => context}} when is_binary(context) <- activity,
|
Activity.direct_conversation_id(activity, for_user)
|
||||||
%Conversation{} = conversation <- Conversation.get_for_ap_id(context),
|
|
||||||
%Participation{id: participation_id} <-
|
|
||||||
Participation.for_user_and_conversation(for_user, conversation) do
|
|
||||||
participation_id
|
|
||||||
else
|
else
|
||||||
{:direct_conversation_id, participation_id} when is_integer(participation_id) ->
|
{:direct_conversation_id, participation_id} when is_integer(participation_id) ->
|
||||||
participation_id
|
participation_id
|
||||||
|
|
|
@ -33,6 +33,8 @@ def perform(
|
||||||
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
|
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
|
||||||
avatar_url = User.avatar_url(actor)
|
avatar_url = User.avatar_url(actor)
|
||||||
object = Object.normalize(activity)
|
object = Object.normalize(activity)
|
||||||
|
user = User.get_cached_by_id(user_id)
|
||||||
|
direct_conversation_id = Activity.direct_conversation_id(activity, user)
|
||||||
|
|
||||||
for subscription <- fetch_subsriptions(user_id),
|
for subscription <- fetch_subsriptions(user_id),
|
||||||
get_in(subscription.data, ["alerts", type]) do
|
get_in(subscription.data, ["alerts", type]) do
|
||||||
|
@ -45,7 +47,8 @@ def perform(
|
||||||
icon: avatar_url,
|
icon: avatar_url,
|
||||||
preferred_locale: "en",
|
preferred_locale: "en",
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
activity_id: activity_id
|
activity_id: activity_id,
|
||||||
|
direct_conversation_id: direct_conversation_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -103,7 +103,7 @@ defp deps do
|
||||||
{:ecto_enum, "~> 1.4"},
|
{:ecto_enum, "~> 1.4"},
|
||||||
{:ecto_sql, "~> 3.2"},
|
{:ecto_sql, "~> 3.2"},
|
||||||
{:postgrex, ">= 0.13.5"},
|
{:postgrex, ">= 0.13.5"},
|
||||||
{:oban, "~> 0.8.1"},
|
{:oban, "~> 0.12.0"},
|
||||||
{:quantum, "~> 2.3"},
|
{:quantum, "~> 2.3"},
|
||||||
{:gettext, "~> 0.15"},
|
{:gettext, "~> 0.15"},
|
||||||
{:comeonin, "~> 4.1.1"},
|
{:comeonin, "~> 4.1.1"},
|
||||||
|
|
8
mix.lock
8
mix.lock
|
@ -23,9 +23,9 @@
|
||||||
"decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"},
|
"decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"},
|
||||||
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"},
|
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"},
|
||||||
"earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"},
|
"earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"},
|
||||||
"ecto": {:hex, :ecto, "3.2.3", "51274df79862845b388733fddcf6f107d0c8c86e27abe7131fa98f8d30761bda", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
|
"ecto": {:hex, :ecto, "3.2.5", "76c864b77948a479e18e69cc1d0f0f4ee7cced1148ffe6a093ff91eba644f0b5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"},
|
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.2.0", "751cea597e8deb616084894dd75cbabfdbe7255ff01e8c058ca13f0353a3921b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
"ecto_sql": {:hex, :ecto_sql, "3.2.2", "d10845bc147b9f61ef485cbf0973c0a337237199bd9bd30dd9542db00aadc26b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0 or ~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"},
|
"esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"},
|
||||||
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"},
|
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"},
|
||||||
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
|
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
||||||
"nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
|
"nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
|
||||||
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
|
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
|
||||||
"oban": {:hex, :oban, "0.8.1", "4bbf62eb1829f856d69aeb5069ac7036afe07db8221a17de2a9169cc7a58a318", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
"oban": {:hex, :oban, "0.12.0", "5477d5ab4a5a201c0b6c89764040ebfc5d2c71c488a36f378016ce5990838f0f", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
|
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
|
||||||
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm"},
|
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm"},
|
||||||
"phoenix": {:hex, :phoenix, "1.4.10", "619e4a545505f562cd294df52294372d012823f4fd9d34a6657a8b242898c255", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
"phoenix": {:hex, :phoenix, "1.4.10", "619e4a545505f562cd294df52294372d012823f4fd9d34a6657a8b242898c255", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"},
|
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"},
|
||||||
"swoosh": {:hex, :swoosh, "0.23.5", "bfd9404bbf5069b1be2ffd317923ce57e58b332e25dbca2a35dedd7820dfee5a", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
|
"swoosh": {:hex, :swoosh, "0.23.5", "bfd9404bbf5069b1be2ffd317923ce57e58b332e25dbca2a35dedd7820dfee5a", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
|
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
|
||||||
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
|
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"},
|
||||||
"tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
|
"tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
|
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.FixMissingFollowingCount do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
"""
|
||||||
|
UPDATE
|
||||||
|
users
|
||||||
|
SET
|
||||||
|
following_count = sub.count
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
users.id AS sub_id
|
||||||
|
,COUNT (following_relationships.id)
|
||||||
|
FROM
|
||||||
|
following_relationships
|
||||||
|
,users
|
||||||
|
WHERE
|
||||||
|
users.id = following_relationships.follower_id
|
||||||
|
AND following_relationships.state = 'accept'
|
||||||
|
GROUP BY
|
||||||
|
users.id
|
||||||
|
) AS sub
|
||||||
|
WHERE
|
||||||
|
users.id = sub.sub_id
|
||||||
|
AND users.local = TRUE
|
||||||
|
;
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
"""
|
||||||
|
UPDATE
|
||||||
|
users
|
||||||
|
SET
|
||||||
|
following_count = 0
|
||||||
|
WHERE
|
||||||
|
following_count IS NULL
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
execute("ALTER TABLE users
|
||||||
|
ALTER COLUMN following_count SET DEFAULT 0,
|
||||||
|
ALTER COLUMN following_count SET NOT NULL
|
||||||
|
")
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
execute("ALTER TABLE users
|
||||||
|
ALTER COLUMN following_count DROP DEFAULT,
|
||||||
|
ALTER COLUMN following_count DROP NOT NULL
|
||||||
|
")
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Integration.FederationTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
@moduletag :federated
|
||||||
|
import Pleroma.Cluster
|
||||||
|
|
||||||
|
setup_all do
|
||||||
|
Pleroma.Cluster.spawn_default_cluster()
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
@federated1 :"federated1@127.0.0.1"
|
||||||
|
describe "federated cluster primitives" do
|
||||||
|
test "within/2 captures local bindings and executes block on remote node" do
|
||||||
|
captured_binding = :captured
|
||||||
|
|
||||||
|
result =
|
||||||
|
within @federated1 do
|
||||||
|
user = Pleroma.Factory.insert(:user)
|
||||||
|
{captured_binding, node(), user}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert {:captured, @federated1, user} = result
|
||||||
|
refute Pleroma.User.get_by_id(user.id)
|
||||||
|
assert user.id == within(@federated1, do: Pleroma.User.get_by_id(user.id)).id
|
||||||
|
end
|
||||||
|
|
||||||
|
test "runs webserver on customized port" do
|
||||||
|
{nickname, url, url_404} =
|
||||||
|
within @federated1 do
|
||||||
|
import Pleroma.Web.Router.Helpers
|
||||||
|
user = Pleroma.Factory.insert(:user)
|
||||||
|
user_url = account_url(Pleroma.Web.Endpoint, :show, user)
|
||||||
|
url_404 = account_url(Pleroma.Web.Endpoint, :show, "not-exists")
|
||||||
|
|
||||||
|
{user.nickname, user_url, url_404}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert {:ok, {{_, 200, _}, _headers, body}} = :httpc.request(~c"#{url}")
|
||||||
|
assert %{"acct" => ^nickname} = Jason.decode!(body)
|
||||||
|
assert {:ok, {{_, 404, _}, _headers, _body}} = :httpc.request(~c"#{url_404}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,218 @@
|
||||||
|
defmodule Pleroma.Cluster do
|
||||||
|
@moduledoc """
|
||||||
|
Facilities for managing a cluster of slave VM's for federated testing.
|
||||||
|
|
||||||
|
## Spawning the federated cluster
|
||||||
|
|
||||||
|
`spawn_cluster/1` spawns a map of slave nodes that are started
|
||||||
|
within the running VM. During startup, the slave node is sent all configuration
|
||||||
|
from the parent node, as well as all code. After receiving configuration and
|
||||||
|
code, the slave then starts all applications currently running on the parent.
|
||||||
|
The configuration passed to `spawn_cluster/1` overrides any parent application
|
||||||
|
configuration for the provided OTP app and key. This is useful for customizing
|
||||||
|
the Ecto database, Phoenix webserver ports, etc.
|
||||||
|
|
||||||
|
For example, to start a single federated VM named ":federated1", with the
|
||||||
|
Pleroma Endpoint running on port 4123, and with a database named
|
||||||
|
"pleroma_test1", you would run:
|
||||||
|
|
||||||
|
endpoint_conf = Application.fetch_env!(:pleroma, Pleroma.Web.Endpoint)
|
||||||
|
repo_conf = Application.fetch_env!(:pleroma, Pleroma.Repo)
|
||||||
|
|
||||||
|
Pleroma.Cluster.spawn_cluster(%{
|
||||||
|
:"federated1@127.0.0.1" => [
|
||||||
|
{:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test1")},
|
||||||
|
{:pleroma, Pleroma.Web.Endpoint,
|
||||||
|
Keyword.merge(endpoint_conf, http: [port: 4011], url: [port: 4011], server: true)}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
*Note*: application configuration for a given key is not merged,
|
||||||
|
so any customization requires first fetching the existing values
|
||||||
|
and merging yourself by providing the merged configuration,
|
||||||
|
such as above with the endpoint config and repo config.
|
||||||
|
|
||||||
|
## Executing code within a remote node
|
||||||
|
|
||||||
|
Use the `within/2` macro to execute code within the context of a remote
|
||||||
|
federated node. The code block captures all local variable bindings from
|
||||||
|
the parent's context and returns the result of the expression after executing
|
||||||
|
it on the remote node. For example:
|
||||||
|
|
||||||
|
import Pleroma.Cluster
|
||||||
|
|
||||||
|
parent_value = 123
|
||||||
|
|
||||||
|
result =
|
||||||
|
within :"federated1@127.0.0.1" do
|
||||||
|
{node(), parent_value}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert result == {:"federated1@127.0.0.1, 123}
|
||||||
|
|
||||||
|
*Note*: while local bindings are captured and available within the block,
|
||||||
|
other parent contexts like required, aliased, or imported modules are not
|
||||||
|
in scope. Those will need to be reimported/aliases/required within the block
|
||||||
|
as `within/2` is a remote procedure call.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@extra_apps Pleroma.Mixfile.application()[:extra_applications]
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Spawns the default Pleroma federated cluster.
|
||||||
|
|
||||||
|
Values before may be customized as needed for the test suite.
|
||||||
|
"""
|
||||||
|
def spawn_default_cluster do
|
||||||
|
endpoint_conf = Application.fetch_env!(:pleroma, Pleroma.Web.Endpoint)
|
||||||
|
repo_conf = Application.fetch_env!(:pleroma, Pleroma.Repo)
|
||||||
|
|
||||||
|
spawn_cluster(%{
|
||||||
|
:"federated1@127.0.0.1" => [
|
||||||
|
{:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test_federated1")},
|
||||||
|
{:pleroma, Pleroma.Web.Endpoint,
|
||||||
|
Keyword.merge(endpoint_conf, http: [port: 4011], url: [port: 4011], server: true)}
|
||||||
|
],
|
||||||
|
:"federated2@127.0.0.1" => [
|
||||||
|
{:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test_federated2")},
|
||||||
|
{:pleroma, Pleroma.Web.Endpoint,
|
||||||
|
Keyword.merge(endpoint_conf, http: [port: 4012], url: [port: 4012], server: true)}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Spawns a configured map of federated nodes.
|
||||||
|
|
||||||
|
See `Pleroma.Cluster` module documentation for details.
|
||||||
|
"""
|
||||||
|
def spawn_cluster(node_configs) do
|
||||||
|
# Turn node into a distributed node with the given long name
|
||||||
|
:net_kernel.start([:"primary@127.0.0.1"])
|
||||||
|
|
||||||
|
# Allow spawned nodes to fetch all code from this node
|
||||||
|
{:ok, _} = :erl_boot_server.start([])
|
||||||
|
allow_boot("127.0.0.1")
|
||||||
|
|
||||||
|
silence_logger_warnings(fn ->
|
||||||
|
node_configs
|
||||||
|
|> Enum.map(&Task.async(fn -> start_slave(&1) end))
|
||||||
|
|> Enum.map(&Task.await(&1, 60_000))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Executes block of code again remote node.
|
||||||
|
|
||||||
|
See `Pleroma.Cluster` module documentation for details.
|
||||||
|
"""
|
||||||
|
defmacro within(node, do: block) do
|
||||||
|
quote do
|
||||||
|
rpc(unquote(node), unquote(__MODULE__), :eval_quoted, [
|
||||||
|
unquote(Macro.escape(block)),
|
||||||
|
binding()
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def eval_quoted(block, binding) do
|
||||||
|
{result, _binding} = Code.eval_quoted(block, binding, __ENV__)
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
defp start_slave({node_host, override_configs}) do
|
||||||
|
log(node_host, "booting federated VM")
|
||||||
|
{:ok, node} = :slave.start(~c"127.0.0.1", node_name(node_host), vm_args())
|
||||||
|
add_code_paths(node)
|
||||||
|
load_apps_and_transfer_configuration(node, override_configs)
|
||||||
|
ensure_apps_started(node)
|
||||||
|
{:ok, node}
|
||||||
|
end
|
||||||
|
|
||||||
|
def rpc(node, module, function, args) do
|
||||||
|
:rpc.block_call(node, module, function, args)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp vm_args do
|
||||||
|
~c"-loader inet -hosts 127.0.0.1 -setcookie #{:erlang.get_cookie()}"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp allow_boot(host) do
|
||||||
|
{:ok, ipv4} = :inet.parse_ipv4_address(~c"#{host}")
|
||||||
|
:ok = :erl_boot_server.add_slave(ipv4)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp add_code_paths(node) do
|
||||||
|
rpc(node, :code, :add_paths, [:code.get_path()])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp load_apps_and_transfer_configuration(node, override_configs) do
|
||||||
|
Enum.each(Application.loaded_applications(), fn {app_name, _, _} ->
|
||||||
|
app_name
|
||||||
|
|> Application.get_all_env()
|
||||||
|
|> Enum.each(fn {key, primary_config} ->
|
||||||
|
rpc(node, Application, :put_env, [app_name, key, primary_config, [persistent: true]])
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
Enum.each(override_configs, fn {app_name, key, val} ->
|
||||||
|
rpc(node, Application, :put_env, [app_name, key, val, [persistent: true]])
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp log(node, msg), do: IO.puts("[#{node}] #{msg}")
|
||||||
|
|
||||||
|
defp ensure_apps_started(node) do
|
||||||
|
loaded_names = Enum.map(Application.loaded_applications(), fn {name, _, _} -> name end)
|
||||||
|
app_names = @extra_apps ++ (loaded_names -- @extra_apps)
|
||||||
|
|
||||||
|
rpc(node, Application, :ensure_all_started, [:mix])
|
||||||
|
rpc(node, Mix, :env, [Mix.env()])
|
||||||
|
rpc(node, __MODULE__, :prepare_database, [])
|
||||||
|
|
||||||
|
log(node, "starting application")
|
||||||
|
|
||||||
|
Enum.reduce(app_names, MapSet.new(), fn app, loaded ->
|
||||||
|
if Enum.member?(loaded, app) do
|
||||||
|
loaded
|
||||||
|
else
|
||||||
|
{:ok, started} = rpc(node, Application, :ensure_all_started, [app])
|
||||||
|
MapSet.union(loaded, MapSet.new(started))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def prepare_database do
|
||||||
|
log(node(), "preparing database")
|
||||||
|
repo_config = Application.get_env(:pleroma, Pleroma.Repo)
|
||||||
|
repo_config[:adapter].storage_down(repo_config)
|
||||||
|
repo_config[:adapter].storage_up(repo_config)
|
||||||
|
|
||||||
|
{:ok, _, _} =
|
||||||
|
Ecto.Migrator.with_repo(Pleroma.Repo, fn repo ->
|
||||||
|
Ecto.Migrator.run(repo, :up, log: false, all: true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
|
||||||
|
{:ok, _} = Application.ensure_all_started(:ex_machina)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp silence_logger_warnings(func) do
|
||||||
|
prev_level = Logger.level()
|
||||||
|
Logger.configure(level: :error)
|
||||||
|
res = func.()
|
||||||
|
Logger.configure(level: prev_level)
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
defp node_name(node_host) do
|
||||||
|
node_host
|
||||||
|
|> to_string()
|
||||||
|
|> String.split("@")
|
||||||
|
|> Enum.at(0)
|
||||||
|
|> String.to_atom()
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,7 +3,8 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
|
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
|
||||||
ExUnit.start(exclude: os_exclude)
|
ExUnit.start(exclude: [:federated | os_exclude])
|
||||||
|
|
||||||
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
|
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
|
||||||
Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)
|
Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)
|
||||||
{:ok, _} = Application.ensure_all_started(:ex_machina)
|
{:ok, _} = Application.ensure_all_started(:ex_machina)
|
||||||
|
|
|
@ -1011,9 +1011,9 @@ test "hide a user from followers" do
|
||||||
{:ok, user} = User.follow(user, user2)
|
{:ok, user} = User.follow(user, user2)
|
||||||
{:ok, _user} = User.deactivate(user)
|
{:ok, _user} = User.deactivate(user)
|
||||||
|
|
||||||
info = User.get_cached_user_info(user2)
|
user2 = User.get_cached_by_id(user2.id)
|
||||||
|
|
||||||
assert info.follower_count == 0
|
assert user2.follower_count == 0
|
||||||
assert [] = User.get_followers(user2)
|
assert [] = User.get_followers(user2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1027,10 +1027,10 @@ test "hide a user from friends" do
|
||||||
|
|
||||||
{:ok, _user} = User.deactivate(user)
|
{:ok, _user} = User.deactivate(user)
|
||||||
|
|
||||||
info = User.get_cached_user_info(user2)
|
user2 = User.get_cached_by_id(user2.id)
|
||||||
|
|
||||||
assert refresh_record(user2).following_count == 0
|
assert refresh_record(user2).following_count == 0
|
||||||
assert info.following_count == 0
|
assert user2.following_count == 0
|
||||||
assert User.following_count(user2) == 0
|
assert User.following_count(user2) == 0
|
||||||
assert [] = User.get_friends(user2)
|
assert [] = User.get_friends(user2)
|
||||||
end
|
end
|
||||||
|
@ -1232,13 +1232,12 @@ test "html_filter_policy returns TwitterText scrubber when rich-text is disabled
|
||||||
describe "caching" do
|
describe "caching" do
|
||||||
test "invalidate_cache works" do
|
test "invalidate_cache works" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
_user_info = User.get_cached_user_info(user)
|
|
||||||
|
|
||||||
|
User.set_cache(user)
|
||||||
User.invalidate_cache(user)
|
User.invalidate_cache(user)
|
||||||
|
|
||||||
{:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
|
{:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
|
||||||
{:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
|
{:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
|
||||||
{:ok, nil} = Cachex.get(:user_cache, "user_info:#{user.id}")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "User.delete() plugs any possible zombie objects" do
|
test "User.delete() plugs any possible zombie objects" do
|
||||||
|
@ -1395,7 +1394,7 @@ test "follower count is updated when a follower is blocked" do
|
||||||
{:ok, _user_relationship} = User.block(user, follower)
|
{:ok, _user_relationship} = User.block(user, follower)
|
||||||
user = refresh_record(user)
|
user = refresh_record(user)
|
||||||
|
|
||||||
assert User.user_info(user).follower_count == 2
|
assert user.follower_count == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "list_inactive_users_query/1" do
|
describe "list_inactive_users_query/1" do
|
||||||
|
@ -1572,51 +1571,6 @@ test "external_users/1 external active users with limit", %{user1: user1, user2:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "set_info_cache/2" do
|
|
||||||
setup do
|
|
||||||
user = insert(:user)
|
|
||||||
{:ok, user: user}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "update from args", %{user: user} do
|
|
||||||
User.set_info_cache(user, %{following_count: 15, follower_count: 18})
|
|
||||||
|
|
||||||
%{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
|
|
||||||
assert followers == 18
|
|
||||||
assert following == 15
|
|
||||||
end
|
|
||||||
|
|
||||||
test "without args", %{user: user} do
|
|
||||||
User.set_info_cache(user, %{})
|
|
||||||
|
|
||||||
%{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
|
|
||||||
assert followers == 0
|
|
||||||
assert following == 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "user_info/2" do
|
|
||||||
setup do
|
|
||||||
user = insert(:user)
|
|
||||||
{:ok, user: user}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "update from args", %{user: user} do
|
|
||||||
%{follower_count: followers, following_count: following} =
|
|
||||||
User.user_info(user, %{following_count: 15, follower_count: 18})
|
|
||||||
|
|
||||||
assert followers == 18
|
|
||||||
assert following == 15
|
|
||||||
end
|
|
||||||
|
|
||||||
test "without args", %{user: user} do
|
|
||||||
%{follower_count: followers, following_count: following} = User.user_info(user)
|
|
||||||
|
|
||||||
assert followers == 0
|
|
||||||
assert following == 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "is_internal_user?/1" do
|
describe "is_internal_user?/1" do
|
||||||
test "non-internal user returns false" do
|
test "non-internal user returns false" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
@ -1673,14 +1627,14 @@ test "updates the counters normally on following/getting a follow when disabled"
|
||||||
ap_enabled: true
|
ap_enabled: true
|
||||||
)
|
)
|
||||||
|
|
||||||
assert User.user_info(other_user).following_count == 0
|
assert other_user.following_count == 0
|
||||||
assert User.user_info(other_user).follower_count == 0
|
assert other_user.follower_count == 0
|
||||||
|
|
||||||
{:ok, user} = Pleroma.User.follow(user, other_user)
|
{:ok, user} = Pleroma.User.follow(user, other_user)
|
||||||
other_user = Pleroma.User.get_by_id(other_user.id)
|
other_user = Pleroma.User.get_by_id(other_user.id)
|
||||||
|
|
||||||
assert User.user_info(user).following_count == 1
|
assert user.following_count == 1
|
||||||
assert User.user_info(other_user).follower_count == 1
|
assert other_user.follower_count == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
test "syncronizes the counters with the remote instance for the followed when enabled" do
|
test "syncronizes the counters with the remote instance for the followed when enabled" do
|
||||||
|
@ -1696,14 +1650,14 @@ test "syncronizes the counters with the remote instance for the followed when en
|
||||||
ap_enabled: true
|
ap_enabled: true
|
||||||
)
|
)
|
||||||
|
|
||||||
assert User.user_info(other_user).following_count == 0
|
assert other_user.following_count == 0
|
||||||
assert User.user_info(other_user).follower_count == 0
|
assert other_user.follower_count == 0
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :external_user_synchronization], true)
|
Pleroma.Config.put([:instance, :external_user_synchronization], true)
|
||||||
{:ok, _user} = User.follow(user, other_user)
|
{:ok, _user} = User.follow(user, other_user)
|
||||||
other_user = User.get_by_id(other_user.id)
|
other_user = User.get_by_id(other_user.id)
|
||||||
|
|
||||||
assert User.user_info(other_user).follower_count == 437
|
assert other_user.follower_count == 437
|
||||||
end
|
end
|
||||||
|
|
||||||
test "syncronizes the counters with the remote instance for the follower when enabled" do
|
test "syncronizes the counters with the remote instance for the follower when enabled" do
|
||||||
|
@ -1719,13 +1673,13 @@ test "syncronizes the counters with the remote instance for the follower when en
|
||||||
ap_enabled: true
|
ap_enabled: true
|
||||||
)
|
)
|
||||||
|
|
||||||
assert User.user_info(other_user).following_count == 0
|
assert other_user.following_count == 0
|
||||||
assert User.user_info(other_user).follower_count == 0
|
assert other_user.follower_count == 0
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :external_user_synchronization], true)
|
Pleroma.Config.put([:instance, :external_user_synchronization], true)
|
||||||
{:ok, other_user} = User.follow(other_user, user)
|
{:ok, other_user} = User.follow(other_user, user)
|
||||||
|
|
||||||
assert User.user_info(other_user).following_count == 152
|
assert other_user.following_count == 152
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ test "it ignores an incoming notice if we already have it" do
|
||||||
assert activity == returned_activity
|
assert activity == returned_activity
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
test "it fetches replied-to activities if we don't have them" do
|
test "it fetches replied-to activities if we don't have them" do
|
||||||
data =
|
data =
|
||||||
File.read!("test/fixtures/mastodon-post-activity.json")
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||||
|
@ -533,6 +534,7 @@ test "it works for incoming announces with an inlined activity" do
|
||||||
assert object.data["content"] == "this is a private toot"
|
assert object.data["content"] == "this is a private toot"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
test "it rejects incoming announces with an inlined activity from another origin" do
|
test "it rejects incoming announces with an inlined activity from another origin" do
|
||||||
data =
|
data =
|
||||||
File.read!("test/fixtures/bogus-mastodon-announce.json")
|
File.read!("test/fixtures/bogus-mastodon-announce.json")
|
||||||
|
@ -814,6 +816,7 @@ test "it fails for incoming deletes with spoofed origin" do
|
||||||
assert Activity.get_by_id(activity.id)
|
assert Activity.get_by_id(activity.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
test "it works for incoming user deletes" do
|
test "it works for incoming user deletes" do
|
||||||
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
|
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
|
||||||
|
|
||||||
|
@ -1749,6 +1752,7 @@ test "returns object with inReplyToAtomUri when denied incoming reply", %{data:
|
||||||
assert modified_object["inReplyToAtomUri"] == ""
|
assert modified_object["inReplyToAtomUri"] == ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
test "returns modified object when allowed incoming reply", %{data: data} do
|
test "returns modified object when allowed incoming reply", %{data: data} do
|
||||||
object_with_reply =
|
object_with_reply =
|
||||||
Map.put(
|
Map.put(
|
||||||
|
@ -1868,6 +1872,7 @@ test "returns nil when cannot normalize object" do
|
||||||
end) =~ "Unsupported URI scheme"
|
end) =~ "Unsupported URI scheme"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
test "returns {:ok, %Object{}} for success case" do
|
test "returns {:ok, %Object{}} for success case" do
|
||||||
assert {:ok, %Object{}} =
|
assert {:ok, %Object{}} =
|
||||||
Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873")
|
Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873")
|
||||||
|
|
|
@ -1923,6 +1923,7 @@ test "with settings in db", %{conn: conn} do
|
||||||
Pleroma.Config.put([:instance, :dynamic_configuration], true)
|
Pleroma.Config.put([:instance, :dynamic_configuration], true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
test "create new config setting in db", %{conn: conn} do
|
test "create new config setting in db", %{conn: conn} do
|
||||||
conn =
|
conn =
|
||||||
post(conn, "/api/pleroma/admin/config", %{
|
post(conn, "/api/pleroma/admin/config", %{
|
||||||
|
|
|
@ -350,7 +350,8 @@ test "represent an embedded relationship" do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert expected == AccountView.render("show.json", %{user: user, for: other_user})
|
assert expected ==
|
||||||
|
AccountView.render("show.json", %{user: refresh_record(user), for: other_user})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns the settings store if the requesting user is the represented user and it's requested specifically" do
|
test "returns the settings store if the requesting user is the represented user and it's requested specifically" do
|
||||||
|
@ -374,6 +375,14 @@ test "sanitizes display names" do
|
||||||
refute result.display_name == "<marquee> username </marquee>"
|
refute result.display_name == "<marquee> username </marquee>"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "never display nil user follow counts" do
|
||||||
|
user = insert(:user, following_count: 0, follower_count: 0)
|
||||||
|
result = AccountView.render("show.json", %{user: user})
|
||||||
|
|
||||||
|
assert result.following_count == 0
|
||||||
|
assert result.followers_count == 0
|
||||||
|
end
|
||||||
|
|
||||||
describe "hiding follows/following" do
|
describe "hiding follows/following" do
|
||||||
test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do
|
test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do
|
||||||
user =
|
user =
|
||||||
|
|
|
@ -15,7 +15,7 @@ defmodule Pleroma.Web.StreamerTest do
|
||||||
alias Pleroma.Web.Streamer.StreamerSocket
|
alias Pleroma.Web.Streamer.StreamerSocket
|
||||||
alias Pleroma.Web.Streamer.Worker
|
alias Pleroma.Web.Streamer.Worker
|
||||||
|
|
||||||
@moduletag needs_streamer: true
|
@moduletag needs_streamer: true, capture_log: true
|
||||||
clear_config_all([:instance, :skip_thread_containment])
|
clear_config_all([:instance, :skip_thread_containment])
|
||||||
|
|
||||||
describe "user streams" do
|
describe "user streams" do
|
||||||
|
|
Loading…
Reference in New Issue