<%= label f, :code, "Recovery code" %>
- <%= text_input f, :code %>
+ <%= text_input f, :code, [autocomplete: false, autocorrect: "off", autocapitalize: "off", autofocus: true, spellcheck: false] %>
<%= hidden_input f, :mfa_token, value: @mfa_token %>
<%= hidden_input f, :state, value: @state %>
<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
diff --git a/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex b/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex
index af6e546b0..af85777eb 100644
--- a/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex
+++ b/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex
@@ -10,7 +10,7 @@
<%= form_for @conn, mfa_verify_path(@conn, :verify), [as: "mfa"], fn f -> %>
<%= label f, :code, "Authentication code" %>
- <%= text_input f, :code %>
+ <%= text_input f, :code, [autocomplete: false, autocorrect: "off", autocapitalize: "off", autofocus: true, pattern: "[0-9]*", spellcheck: false] %>
<%= hidden_input f, :mfa_token, value: @mfa_token %>
<%= hidden_input f, :state, value: @state %>
<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 5cfb385ac..2294d9d0d 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -19,6 +19,7 @@ def register_user(params, opts \\ []) do
|> Map.put(:nickname, params[:username])
|> Map.put(:name, Map.get(params, :fullname, params[:username]))
|> Map.put(:password_confirmation, params[:password])
+ |> Map.put(:registration_reason, params[:reason])
if Pleroma.Config.get([:instance, :registrations_open]) do
create_user(params, opts)
@@ -44,6 +45,7 @@ defp create_user(params, opts) do
case User.register(changeset) do
{:ok, user} ->
+ maybe_notify_admins(user)
{:ok, user}
{:error, changeset} ->
@@ -56,6 +58,18 @@ defp create_user(params, opts) do
end
end
+ defp maybe_notify_admins(%User{} = account) do
+ if Pleroma.Config.get([:instance, :account_approval_required]) do
+ User.all_superusers()
+ |> Enum.filter(fn user -> not is_nil(user.email) end)
+ |> Enum.each(fn superuser ->
+ superuser
+ |> Pleroma.Emails.AdminEmail.new_unapproved_registration(account)
+ |> Pleroma.Emails.Mailer.deliver_async()
+ end)
+ end
+ end
+
def password_reset(nickname_or_email) do
with true <- is_binary(nickname_or_email),
%User{local: true, email: email} = user when is_binary(email) <-
diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex
index f739dacb6..b1669d198 100644
--- a/lib/pleroma/web/views/masto_fe_view.ex
+++ b/lib/pleroma/web/views/masto_fe_view.ex
@@ -9,36 +9,6 @@ defmodule Pleroma.Web.MastoFEView do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.CustomEmojiView
- @default_settings %{
- onboarded: true,
- home: %{
- shows: %{
- reblog: true,
- reply: true
- }
- },
- notifications: %{
- alerts: %{
- follow: true,
- favourite: true,
- reblog: true,
- mention: true
- },
- shows: %{
- follow: true,
- favourite: true,
- reblog: true,
- mention: true
- },
- sounds: %{
- follow: true,
- favourite: true,
- reblog: true,
- mention: true
- }
- }
- }
-
def initial_state(token, user, custom_emojis) do
limit = Config.get([:instance, :limit])
@@ -86,7 +56,7 @@ def initial_state(token, user, custom_emojis) do
"video\/mp4"
]
},
- settings: user.mastofe_settings || @default_settings,
+ settings: user.mastofe_settings || %{},
push_subscription: nil,
accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)},
custom_emojis: render(CustomEmojiView, "index.json", custom_emojis: custom_emojis),
diff --git a/mix.exs b/mix.exs
index 741f917e6..a14b0c51a 100644
--- a/mix.exs
+++ b/mix.exs
@@ -135,30 +135,29 @@ defp deps do
{:poison, "~> 3.0", override: true},
# {:tesla, "~> 1.3", override: true},
{:tesla,
- git: "https://git.pleroma.social/pleroma/elixir-libraries/tesla.git",
- ref: "61b7503cef33f00834f78ddfafe0d5d9dec2270b",
- override: true},
+ github: "teamon/tesla", ref: "af3707078b10793f6a534938e56b963aff82fe3c", override: true},
{:castore, "~> 0.1"},
{:cowlib, "~> 2.8", override: true},
{:gun,
- github: "ninenines/gun", ref: "e1a69b36b180a574c0ac314ced9613fdd52312cc", override: true},
+ github: "ninenines/gun", ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", override: true},
{:jason, "~> 1.0"},
{:mogrify, "~> 0.6.1"},
{:ex_aws, "~> 2.1"},
{:ex_aws_s3, "~> 2.0"},
{:sweet_xml, "~> 0.6.6"},
- {:earmark, "~> 1.3"},
+ {:earmark, "1.4.3"},
{:bbcode_pleroma, "~> 0.2.0"},
{:ex_machina, "~> 2.3", only: :test},
{:credo, "~> 1.1.0", only: [:dev, :test], runtime: false},
{:mock, "~> 0.3.3", only: :test},
{:crypt,
- git: "https://github.com/msantos/crypt", ref: "f63a705f92c26955977ee62a313012e309a4d77a"},
+ git: "https://github.com/msantos/crypt.git",
+ ref: "f63a705f92c26955977ee62a313012e309a4d77a"},
{:cors_plug, "~> 1.5"},
{:ex_doc, "~> 0.21", only: :dev, runtime: false},
{:web_push_encryption, "~> 0.2.1"},
{:swoosh,
- git: "https://github.com/swoosh/swoosh",
+ git: "https://github.com/swoosh/swoosh.git",
ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5",
override: true},
{:phoenix_swoosh, "~> 0.2"},
@@ -168,9 +167,7 @@ defp deps do
{:floki, "~> 0.25"},
{:timex, "~> 3.5"},
{:ueberauth, "~> 0.4"},
- {:auto_linker,
- git: "https://git.pleroma.social/pleroma/auto_linker.git",
- ref: "95e8188490e97505c56636c1379ffdf036c1fdde"},
+ {:linkify, "~> 0.2.0"},
{:http_signatures,
git: "https://git.pleroma.social/pleroma/http_signatures.git",
ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"},
@@ -191,6 +188,9 @@ defp deps do
{:plug_static_index_html, "~> 1.0.0"},
{:excoveralls, "~> 0.12.1", only: :test},
{:flake_id, "~> 0.1.0"},
+ {:concurrent_limiter,
+ git: "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter.git",
+ ref: "8eee96c6ba39b9286ec44c51c52d9f2758951365"},
{:remote_ip,
git: "https://git.pleroma.social/pleroma/remote_ip.git",
ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"},
diff --git a/mix.lock b/mix.lock
index f801f9e0c..80679cded 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,6 +1,5 @@
%{
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
- "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "95e8188490e97505c56636c1379ffdf036c1fdde", [ref: "95e8188490e97505c56636c1379ffdf036c1fdde"]},
"base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "3b29948de2013d3f93aa898c884a9dff847e7aec75d9d6d8c1dc4c61c2716c42"},
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"bbcode": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/bbcode.git", "f2d267675e9a7e1ad1ea9beb4cc23382762b66c2", [ref: "v0.2.0"]},
@@ -15,13 +14,14 @@
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.3.1", "7fe612b739c78c9c1a75186ef2d322ce4d25032d119823269d0aa1e2f1e20025", [:mix], [], "hexpm", "d6222483060c17f0977fad1b7401ef0c5863c985a64352755f366aee3799c245"},
+ "concurrent_limiter": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter.git", "8eee96c6ba39b9286ec44c51c52d9f2758951365", [ref: "8eee96c6ba39b9286ec44c51c52d9f2758951365"]},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
"cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9af027d20dc12dd0c4345a6b87247e0c62965871feea0bfecf9764648b02cc69"},
"cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "04fd8c6a39edc6aaa9c26123009200fc61f92a3a94f3178c527b70b767c6e605"},
"cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"},
"credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d0bbd3222607ccaaac5c0340f7f525c627ae4d7aee6c8c8c108922620c5b6446"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
- "crypt": {:git, "https://github.com/msantos/crypt", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]},
+ "crypt": {:git, "https://github.com/msantos/crypt.git", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
"db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
@@ -49,7 +49,7 @@
"gen_stage": {:hex, :gen_stage, "0.14.3", "d0c66f1c87faa301c1a85a809a3ee9097a4264b2edf7644bf5c123237ef732bf", [:mix], [], "hexpm"},
"gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.17.4", "f13088e1ec10ce01665cf25f5ff779e7df3f2dc71b37084976cf89d1aa124d5c", [:mix], [], "hexpm", "3c75b5ea8288e2ee7ea503ff9e30dfe4d07ad3c054576a6e60040e79a801e14d"},
- "gun": {:git, "https://github.com/ninenines/gun.git", "e1a69b36b180a574c0ac314ced9613fdd52312cc", [ref: "e1a69b36b180a574c0ac314ced9613fdd52312cc"]},
+ "gun": {:git, "https://github.com/ninenines/gun.git", "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", [ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327"]},
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
"html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm", "30efab070904eb897ff05cd52fa61c1025d7f8ef3a9ca250bc4e6513d16c32de"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
@@ -62,6 +62,7 @@
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
+ "linkify": {:hex, :linkify, "0.2.0", "2518bbbea21d2caa9d372424e1ad845b640c6630e2d016f1bd1f518f9ebcca28", [:mix], [], "hexpm", "b8ca8a68b79e30b7938d6c996085f3db14939f29538a59ca5101988bb7f917f6"},
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"},
"meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm", "d34f013c156db51ad57cc556891b9720e6a1c1df5fe2e15af999c84d6cebeb1a"},
@@ -104,10 +105,10 @@
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"},
- "swoosh": {:git, "https://github.com/swoosh/swoosh", "c96e0ca8a00d8f211ec1f042a4626b09f249caa5", [ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5"]},
+ "swoosh": {:git, "https://github.com/swoosh/swoosh.git", "c96e0ca8a00d8f211ec1f042a4626b09f249caa5", [ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5"]},
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
"telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
- "tesla": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/tesla.git", "61b7503cef33f00834f78ddfafe0d5d9dec2270b", [ref: "61b7503cef33f00834f78ddfafe0d5d9dec2270b"]},
+ "tesla": {:git, "https://github.com/teamon/tesla.git", "af3707078b10793f6a534938e56b963aff82fe3c", [ref: "af3707078b10793f6a534938e56b963aff82fe3c"]},
"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", "f354efb2400dd7a80fd9eb6c8419068c4f632da4ac47f3d8822d6e33f08bc852"},
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
"tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"},
diff --git a/priv/repo/migrations/20200626163359_rename_notification_privacy_option.exs b/priv/repo/migrations/20200626163359_rename_notification_privacy_option.exs
new file mode 100644
index 000000000..06d7f7272
--- /dev/null
+++ b/priv/repo/migrations/20200626163359_rename_notification_privacy_option.exs
@@ -0,0 +1,19 @@
+defmodule Pleroma.Repo.Migrations.RenameNotificationPrivacyOption do
+ use Ecto.Migration
+
+ def up do
+ execute(
+ "UPDATE users SET notification_settings = notification_settings - 'privacy_option' || jsonb_build_object('hide_notification_contents', notification_settings->'privacy_option')
+where notification_settings ? 'privacy_option'
+and local"
+ )
+ end
+
+ def down do
+ execute(
+ "UPDATE users SET notification_settings = notification_settings - 'hide_notification_contents' || jsonb_build_object('privacy_option', notification_settings->'hide_notification_contents')
+where notification_settings ? 'hide_notification_contents'
+and local"
+ )
+ end
+end
diff --git a/priv/repo/migrations/20200712234852_add_approval_fields_to_users.exs b/priv/repo/migrations/20200712234852_add_approval_fields_to_users.exs
new file mode 100644
index 000000000..43f741a5b
--- /dev/null
+++ b/priv/repo/migrations/20200712234852_add_approval_fields_to_users.exs
@@ -0,0 +1,10 @@
+defmodule Pleroma.Repo.Migrations.AddApprovalFieldsToUsers do
+ use Ecto.Migration
+
+ def change do
+ alter table(:users) do
+ add(:approval_pending, :boolean)
+ add(:registration_reason, :text)
+ end
+ end
+end
diff --git a/priv/repo/migrations/20200716195806_autolinker_to_linkify.exs b/priv/repo/migrations/20200716195806_autolinker_to_linkify.exs
new file mode 100644
index 000000000..570acba84
--- /dev/null
+++ b/priv/repo/migrations/20200716195806_autolinker_to_linkify.exs
@@ -0,0 +1,36 @@
+defmodule Pleroma.Repo.Migrations.AutolinkerToLinkify do
+ use Ecto.Migration
+ alias Pleroma.ConfigDB
+
+ @autolinker_path %{group: :auto_linker, key: :opts}
+ @linkify_path %{group: :pleroma, key: Pleroma.Formatter}
+
+ @compat_opts [:class, :rel, :new_window, :truncate, :strip_prefix, :extra]
+
+ def change do
+ with {:ok, {old, new}} <- maybe_get_params() do
+ move_config(old, new)
+ end
+ end
+
+ defp move_config(%{} = old, %{} = new) do
+ {:ok, _} = ConfigDB.update_or_create(new)
+ {:ok, _} = ConfigDB.delete(old)
+ :ok
+ end
+
+ defp maybe_get_params() do
+ with %ConfigDB{value: opts} <- ConfigDB.get_by_params(@autolinker_path),
+ opts <- transform_opts(opts),
+ %{} = linkify_params <- Map.put(@linkify_path, :value, opts) do
+ {:ok, {@autolinker_path, linkify_params}}
+ end
+ end
+
+ def transform_opts(opts) when is_list(opts) do
+ opts
+ |> Enum.into(%{})
+ |> Map.take(@compat_opts)
+ |> Map.to_list()
+ end
+end
diff --git a/priv/repo/migrations/20200722185515_fix_malformed_formatter_config.exs b/priv/repo/migrations/20200722185515_fix_malformed_formatter_config.exs
new file mode 100644
index 000000000..77b760825
--- /dev/null
+++ b/priv/repo/migrations/20200722185515_fix_malformed_formatter_config.exs
@@ -0,0 +1,26 @@
+defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfig do
+ use Ecto.Migration
+ alias Pleroma.ConfigDB
+
+ @config_path %{group: :pleroma, key: Pleroma.Formatter}
+
+ def change do
+ with %ConfigDB{value: %{} = opts} <- ConfigDB.get_by_params(@config_path),
+ fixed_opts <- Map.to_list(opts) do
+ fix_config(fixed_opts)
+ else
+ _ -> :skipped
+ end
+ end
+
+ defp fix_config(fixed_opts) when is_list(fixed_opts) do
+ {:ok, _} =
+ ConfigDB.update_or_create(%{
+ group: :pleroma,
+ key: Pleroma.Formatter,
+ value: fixed_opts
+ })
+
+ :ok
+ end
+end
diff --git a/priv/repo/migrations/20200724133313_move_welcome_settings.exs b/priv/repo/migrations/20200724133313_move_welcome_settings.exs
new file mode 100644
index 000000000..323a8fcee
--- /dev/null
+++ b/priv/repo/migrations/20200724133313_move_welcome_settings.exs
@@ -0,0 +1,94 @@
+defmodule Pleroma.Repo.Migrations.MoveWelcomeSettings do
+ use Ecto.Migration
+
+ alias Pleroma.ConfigDB
+
+ @old_keys [:welcome_user_nickname, :welcome_message]
+
+ def up do
+ with {:ok, config, {keep_values, move_values}} <- get_old_values() do
+ insert_welcome_settings(move_values)
+ update_instance_config(config, keep_values)
+ end
+ end
+
+ def down do
+ with {:ok, welcome_config, revert_values} <- get_revert_values() do
+ revert_instance_config(revert_values)
+ Pleroma.Repo.delete(welcome_config)
+ end
+ end
+
+ defp insert_welcome_settings([_ | _] = values) do
+ unless String.trim(values[:welcome_message]) == "" do
+ config_values = [
+ direct_message: %{
+ enabled: true,
+ sender_nickname: values[:welcome_user_nickname],
+ message: values[:welcome_message]
+ },
+ email: %{
+ enabled: false,
+ sender: nil,
+ subject: "Welcome to <%= instance_name %>",
+ html: "Welcome to <%= instance_name %>",
+ text: "Welcome to <%= instance_name %>"
+ }
+ ]
+
+ {:ok, _} =
+ %ConfigDB{}
+ |> ConfigDB.changeset(%{group: :pleroma, key: :welcome, value: config_values})
+ |> Pleroma.Repo.insert()
+ end
+
+ :ok
+ end
+
+ defp insert_welcome_settings(_), do: :noop
+
+ defp revert_instance_config(%{} = revert_values) do
+ values = [
+ welcome_user_nickname: revert_values[:sender_nickname],
+ welcome_message: revert_values[:message]
+ ]
+
+ ConfigDB.update_or_create(%{group: :pleroma, key: :instance, value: values})
+ end
+
+ defp revert_instance_config(_), do: :noop
+
+ defp update_instance_config(config, values) do
+ {:ok, _} =
+ config
+ |> ConfigDB.changeset(%{value: values})
+ |> Pleroma.Repo.update()
+
+ :ok
+ end
+
+ defp get_revert_values do
+ config = ConfigDB.get_by_params(%{group: :pleroma, key: :welcome})
+
+ cond do
+ is_nil(config) -> {:noop, nil, nil}
+ true -> {:ok, config, config.value[:direct_message]}
+ end
+ end
+
+ defp get_old_values do
+ config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
+
+ cond do
+ is_nil(config) ->
+ {:noop, config, {}}
+
+ is_binary(config.value[:welcome_message]) ->
+ {:ok, config,
+ {Keyword.drop(config.value, @old_keys), Keyword.take(config.value, @old_keys)}}
+
+ true ->
+ {:ok, config, {Keyword.drop(config.value, @old_keys), []}}
+ end
+ end
+end
diff --git a/priv/static/index.html b/priv/static/index.html
index 80820166a..2257dec35 100644
--- a/priv/static/index.html
+++ b/priv/static/index.html
@@ -1 +1 @@
-
Pleroma
\ No newline at end of file
+
Pleroma
\ No newline at end of file
diff --git a/priv/static/static/css/app.77b1644622e3bae24b6b.css b/priv/static/static/css/app.6dbc7dea4fc148c85860.css
similarity index 99%
rename from priv/static/static/css/app.77b1644622e3bae24b6b.css
rename to priv/static/static/css/app.6dbc7dea4fc148c85860.css
index 8038882c0..3927e3b77 100644
Binary files a/priv/static/static/css/app.77b1644622e3bae24b6b.css and b/priv/static/static/css/app.6dbc7dea4fc148c85860.css differ
diff --git a/priv/static/static/css/app.77b1644622e3bae24b6b.css.map b/priv/static/static/css/app.6dbc7dea4fc148c85860.css.map
similarity index 99%
rename from priv/static/static/css/app.77b1644622e3bae24b6b.css.map
rename to priv/static/static/css/app.6dbc7dea4fc148c85860.css.map
index 4b042ef35..963d5b3b8 100644
--- a/priv/static/static/css/app.77b1644622e3bae24b6b.css.map
+++ b/priv/static/static/css/app.6dbc7dea4fc148c85860.css.map
@@ -1 +1 @@
-{"version":3,"sources":["webpack:///./src/components/tab_switcher/tab_switcher.scss","webpack:///./src/hocs/with_load_more/with_load_more.scss"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C;ACtOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C","file":"static/css/app.77b1644622e3bae24b6b.css","sourcesContent":[".tab-switcher {\n display: -ms-flexbox;\n display: flex;\n}\n.tab-switcher .tab-icon {\n font-size: 2em;\n display: block;\n}\n.tab-switcher.top-tabs {\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher.top-tabs > .tabs {\n width: 100%;\n overflow-y: hidden;\n overflow-x: auto;\n padding-top: 5px;\n -ms-flex-direction: row;\n flex-direction: row;\n}\n.tab-switcher.top-tabs > .tabs::after, .tab-switcher.top-tabs > .tabs::before {\n content: \"\";\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}\n.tab-switcher.top-tabs > .tabs .tab-wrapper {\n height: 28px;\n}\n.tab-switcher.top-tabs > .tabs .tab-wrapper:not(.active)::after {\n left: 0;\n right: 0;\n bottom: 0;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}\n.tab-switcher.top-tabs > .tabs .tab {\n width: 100%;\n min-width: 1px;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n padding-bottom: 99px;\n margin-bottom: -93px;\n}\n.tab-switcher.top-tabs .contents.scrollable-tabs {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n}\n.tab-switcher.side-tabs {\n -ms-flex-direction: row;\n flex-direction: row;\n}\n@media all and (max-width: 800px) {\n .tab-switcher.side-tabs {\n overflow-x: auto;\n }\n}\n.tab-switcher.side-tabs > .contents {\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n}\n.tab-switcher.side-tabs > .tabs {\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n overflow-y: auto;\n overflow-x: hidden;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher.side-tabs > .tabs::after, .tab-switcher.side-tabs > .tabs::before {\n -ms-flex-negative: 0;\n flex-shrink: 0;\n -ms-flex-preferred-size: 0.5em;\n flex-basis: 0.5em;\n content: \"\";\n border-right: 1px solid;\n border-right-color: #222;\n border-right-color: var(--border, #222);\n}\n.tab-switcher.side-tabs > .tabs::after {\n -ms-flex-positive: 1;\n flex-grow: 1;\n}\n.tab-switcher.side-tabs > .tabs::before {\n -ms-flex-positive: 0;\n flex-grow: 0;\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper {\n min-width: 10em;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n@media all and (max-width: 800px) {\n .tab-switcher.side-tabs > .tabs .tab-wrapper {\n min-width: 1em;\n }\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper:not(.active)::after {\n top: 0;\n right: 0;\n bottom: 0;\n border-right: 1px solid;\n border-right-color: #222;\n border-right-color: var(--border, #222);\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper::before {\n -ms-flex: 0 0 6px;\n flex: 0 0 6px;\n content: \"\";\n border-right: 1px solid;\n border-right-color: #222;\n border-right-color: var(--border, #222);\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper:last-child .tab {\n margin-bottom: 0;\n}\n.tab-switcher.side-tabs > .tabs .tab {\n -ms-flex: 1;\n flex: 1;\n box-sizing: content-box;\n min-width: 10em;\n min-width: 1px;\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n padding-left: 1em;\n padding-right: calc(1em + 200px);\n margin-right: -200px;\n margin-left: 1em;\n}\n@media all and (max-width: 800px) {\n .tab-switcher.side-tabs > .tabs .tab {\n padding-left: 0.25em;\n padding-right: calc(.25em + 200px);\n margin-right: calc(.25em - 200px);\n margin-left: 0.25em;\n }\n .tab-switcher.side-tabs > .tabs .tab .text {\n display: none;\n }\n}\n.tab-switcher .contents {\n -ms-flex: 1 0 auto;\n flex: 1 0 auto;\n min-height: 0px;\n}\n.tab-switcher .contents .hidden {\n display: none;\n}\n.tab-switcher .contents .full-height:not(.hidden) {\n height: 100%;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher .contents .full-height:not(.hidden) > *:not(.mobile-label) {\n -ms-flex: 1;\n flex: 1;\n}\n.tab-switcher .contents.scrollable-tabs {\n overflow-y: auto;\n}\n.tab-switcher .tab {\n position: relative;\n white-space: nowrap;\n padding: 6px 1em;\n background-color: #182230;\n background-color: var(--tab, #182230);\n}\n.tab-switcher .tab, .tab-switcher .tab:active .tab-icon {\n color: #b9b9ba;\n color: var(--tabText, #b9b9ba);\n}\n.tab-switcher .tab:not(.active) {\n z-index: 4;\n}\n.tab-switcher .tab:not(.active):hover {\n z-index: 6;\n}\n.tab-switcher .tab.active {\n background: transparent;\n z-index: 5;\n color: #b9b9ba;\n color: var(--tabActiveText, #b9b9ba);\n}\n.tab-switcher .tab img {\n max-height: 26px;\n vertical-align: top;\n margin-top: -5px;\n}\n.tab-switcher .tabs {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n box-sizing: border-box;\n}\n.tab-switcher .tabs::after, .tab-switcher .tabs::before {\n display: block;\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n}\n.tab-switcher .tab-wrapper {\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n}\n.tab-switcher .tab-wrapper:not(.active)::after {\n content: \"\";\n position: absolute;\n z-index: 7;\n}\n.tab-switcher .mobile-label {\n padding-left: 0.3em;\n padding-bottom: 0.25em;\n margin-top: 0.5em;\n margin-left: 0.2em;\n margin-bottom: 0.25em;\n border-bottom: 1px solid var(--border, #222);\n}\n@media all and (min-width: 800px) {\n .tab-switcher .mobile-label {\n display: none;\n }\n}",".with-load-more-footer {\n padding: 10px;\n text-align: center;\n border-top: 1px solid;\n border-top-color: #222;\n border-top-color: var(--border, #222);\n}\n.with-load-more-footer .error {\n font-size: 14px;\n}\n.with-load-more-footer a {\n cursor: pointer;\n}"],"sourceRoot":""}
\ No newline at end of file
+{"version":3,"sources":["webpack:///./src/components/tab_switcher/tab_switcher.scss","webpack:///./src/hocs/with_load_more/with_load_more.scss"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C;ACtOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C","file":"static/css/app.6dbc7dea4fc148c85860.css","sourcesContent":[".tab-switcher {\n display: -ms-flexbox;\n display: flex;\n}\n.tab-switcher .tab-icon {\n font-size: 2em;\n display: block;\n}\n.tab-switcher.top-tabs {\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher.top-tabs > .tabs {\n width: 100%;\n overflow-y: hidden;\n overflow-x: auto;\n padding-top: 5px;\n -ms-flex-direction: row;\n flex-direction: row;\n}\n.tab-switcher.top-tabs > .tabs::after, .tab-switcher.top-tabs > .tabs::before {\n content: \"\";\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}\n.tab-switcher.top-tabs > .tabs .tab-wrapper {\n height: 28px;\n}\n.tab-switcher.top-tabs > .tabs .tab-wrapper:not(.active)::after {\n left: 0;\n right: 0;\n bottom: 0;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}\n.tab-switcher.top-tabs > .tabs .tab {\n width: 100%;\n min-width: 1px;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n padding-bottom: 99px;\n margin-bottom: -93px;\n}\n.tab-switcher.top-tabs .contents.scrollable-tabs {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n}\n.tab-switcher.side-tabs {\n -ms-flex-direction: row;\n flex-direction: row;\n}\n@media all and (max-width: 800px) {\n .tab-switcher.side-tabs {\n overflow-x: auto;\n }\n}\n.tab-switcher.side-tabs > .contents {\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n}\n.tab-switcher.side-tabs > .tabs {\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n overflow-y: auto;\n overflow-x: hidden;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher.side-tabs > .tabs::after, .tab-switcher.side-tabs > .tabs::before {\n -ms-flex-negative: 0;\n flex-shrink: 0;\n -ms-flex-preferred-size: 0.5em;\n flex-basis: 0.5em;\n content: \"\";\n border-right: 1px solid;\n border-right-color: #222;\n border-right-color: var(--border, #222);\n}\n.tab-switcher.side-tabs > .tabs::after {\n -ms-flex-positive: 1;\n flex-grow: 1;\n}\n.tab-switcher.side-tabs > .tabs::before {\n -ms-flex-positive: 0;\n flex-grow: 0;\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper {\n min-width: 10em;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n@media all and (max-width: 800px) {\n .tab-switcher.side-tabs > .tabs .tab-wrapper {\n min-width: 1em;\n }\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper:not(.active)::after {\n top: 0;\n right: 0;\n bottom: 0;\n border-right: 1px solid;\n border-right-color: #222;\n border-right-color: var(--border, #222);\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper::before {\n -ms-flex: 0 0 6px;\n flex: 0 0 6px;\n content: \"\";\n border-right: 1px solid;\n border-right-color: #222;\n border-right-color: var(--border, #222);\n}\n.tab-switcher.side-tabs > .tabs .tab-wrapper:last-child .tab {\n margin-bottom: 0;\n}\n.tab-switcher.side-tabs > .tabs .tab {\n -ms-flex: 1;\n flex: 1;\n box-sizing: content-box;\n min-width: 10em;\n min-width: 1px;\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n padding-left: 1em;\n padding-right: calc(1em + 200px);\n margin-right: -200px;\n margin-left: 1em;\n}\n@media all and (max-width: 800px) {\n .tab-switcher.side-tabs > .tabs .tab {\n padding-left: 0.25em;\n padding-right: calc(.25em + 200px);\n margin-right: calc(.25em - 200px);\n margin-left: 0.25em;\n }\n .tab-switcher.side-tabs > .tabs .tab .text {\n display: none;\n }\n}\n.tab-switcher .contents {\n -ms-flex: 1 0 auto;\n flex: 1 0 auto;\n min-height: 0px;\n}\n.tab-switcher .contents .hidden {\n display: none;\n}\n.tab-switcher .contents .full-height:not(.hidden) {\n height: 100%;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher .contents .full-height:not(.hidden) > *:not(.mobile-label) {\n -ms-flex: 1;\n flex: 1;\n}\n.tab-switcher .contents.scrollable-tabs {\n overflow-y: auto;\n}\n.tab-switcher .tab {\n position: relative;\n white-space: nowrap;\n padding: 6px 1em;\n background-color: #182230;\n background-color: var(--tab, #182230);\n}\n.tab-switcher .tab, .tab-switcher .tab:active .tab-icon {\n color: #b9b9ba;\n color: var(--tabText, #b9b9ba);\n}\n.tab-switcher .tab:not(.active) {\n z-index: 4;\n}\n.tab-switcher .tab:not(.active):hover {\n z-index: 6;\n}\n.tab-switcher .tab.active {\n background: transparent;\n z-index: 5;\n color: #b9b9ba;\n color: var(--tabActiveText, #b9b9ba);\n}\n.tab-switcher .tab img {\n max-height: 26px;\n vertical-align: top;\n margin-top: -5px;\n}\n.tab-switcher .tabs {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n box-sizing: border-box;\n}\n.tab-switcher .tabs::after, .tab-switcher .tabs::before {\n display: block;\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n}\n.tab-switcher .tab-wrapper {\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n}\n.tab-switcher .tab-wrapper:not(.active)::after {\n content: \"\";\n position: absolute;\n z-index: 7;\n}\n.tab-switcher .mobile-label {\n padding-left: 0.3em;\n padding-bottom: 0.25em;\n margin-top: 0.5em;\n margin-left: 0.2em;\n margin-bottom: 0.25em;\n border-bottom: 1px solid var(--border, #222);\n}\n@media all and (min-width: 800px) {\n .tab-switcher .mobile-label {\n display: none;\n }\n}",".with-load-more-footer {\n padding: 10px;\n text-align: center;\n border-top: 1px solid;\n border-top-color: #222;\n border-top-color: var(--border, #222);\n}\n.with-load-more-footer .error {\n font-size: 14px;\n}\n.with-load-more-footer a {\n cursor: pointer;\n}"],"sourceRoot":""}
\ No newline at end of file
diff --git a/priv/static/static/font/fontello.1594374054351.woff2 b/priv/static/static/font/fontello.1594374054351.woff2
deleted file mode 100644
index cb214aab3..000000000
Binary files a/priv/static/static/font/fontello.1594374054351.woff2 and /dev/null differ
diff --git a/priv/static/static/font/fontello.1594374054351.eot b/priv/static/static/font/fontello.1594823398494.eot
similarity index 99%
rename from priv/static/static/font/fontello.1594374054351.eot
rename to priv/static/static/font/fontello.1594823398494.eot
index 62b619386..12e6beabf 100644
Binary files a/priv/static/static/font/fontello.1594374054351.eot and b/priv/static/static/font/fontello.1594823398494.eot differ
diff --git a/priv/static/static/font/fontello.1594374054351.svg b/priv/static/static/font/fontello.1594823398494.svg
similarity index 100%
rename from priv/static/static/font/fontello.1594374054351.svg
rename to priv/static/static/font/fontello.1594823398494.svg
diff --git a/priv/static/static/font/fontello.1594374054351.ttf b/priv/static/static/font/fontello.1594823398494.ttf
similarity index 99%
rename from priv/static/static/font/fontello.1594374054351.ttf
rename to priv/static/static/font/fontello.1594823398494.ttf
index be55bef81..6f21845a8 100644
Binary files a/priv/static/static/font/fontello.1594374054351.ttf and b/priv/static/static/font/fontello.1594823398494.ttf differ
diff --git a/priv/static/static/font/fontello.1594374054351.woff b/priv/static/static/font/fontello.1594823398494.woff
similarity index 96%
rename from priv/static/static/font/fontello.1594374054351.woff
rename to priv/static/static/font/fontello.1594823398494.woff
index 115945f70..a7cd098f4 100644
Binary files a/priv/static/static/font/fontello.1594374054351.woff and b/priv/static/static/font/fontello.1594823398494.woff differ
diff --git a/priv/static/static/font/fontello.1594823398494.woff2 b/priv/static/static/font/fontello.1594823398494.woff2
new file mode 100644
index 000000000..c61bf111a
Binary files /dev/null and b/priv/static/static/font/fontello.1594823398494.woff2 differ
diff --git a/priv/static/static/fontello.1589385935077.css b/priv/static/static/fontello.1589385935077.css
deleted file mode 100644
index 746492163..000000000
Binary files a/priv/static/static/fontello.1589385935077.css and /dev/null differ
diff --git a/priv/static/static/fontello.1594030805019.css b/priv/static/static/fontello.1594030805019.css
deleted file mode 100644
index 9251070fe..000000000
Binary files a/priv/static/static/fontello.1594030805019.css and /dev/null differ
diff --git a/priv/static/static/fontello.1594134783339.css b/priv/static/static/fontello.1594134783339.css
deleted file mode 100644
index ff35edaba..000000000
Binary files a/priv/static/static/fontello.1594134783339.css and /dev/null differ
diff --git a/priv/static/static/fontello.1594374054351.css b/priv/static/static/fontello.1594823398494.css
similarity index 90%
rename from priv/static/static/fontello.1594374054351.css
rename to priv/static/static/fontello.1594823398494.css
index 6dea8ee3e..fe61b94c6 100644
Binary files a/priv/static/static/fontello.1594374054351.css and b/priv/static/static/fontello.1594823398494.css differ
diff --git a/priv/static/static/fontello.json b/priv/static/static/fontello.json
old mode 100755
new mode 100644
diff --git a/priv/static/static/js/10.2823375ec309b971aaea.js b/priv/static/static/js/10.2823375ec309b971aaea.js
deleted file mode 100644
index 8f34c42ea..000000000
Binary files a/priv/static/static/js/10.2823375ec309b971aaea.js and /dev/null differ
diff --git a/priv/static/static/js/10.5ef4671883649cf93524.js b/priv/static/static/js/10.5ef4671883649cf93524.js
new file mode 100644
index 000000000..6819c854b
Binary files /dev/null and b/priv/static/static/js/10.5ef4671883649cf93524.js differ
diff --git a/priv/static/static/js/10.2823375ec309b971aaea.js.map b/priv/static/static/js/10.5ef4671883649cf93524.js.map
similarity index 56%
rename from priv/static/static/js/10.2823375ec309b971aaea.js.map
rename to priv/static/static/js/10.5ef4671883649cf93524.js.map
index 8933e2336..95fa2207e 100644
Binary files a/priv/static/static/js/10.2823375ec309b971aaea.js.map and b/priv/static/static/js/10.5ef4671883649cf93524.js.map differ
diff --git a/priv/static/static/js/11.2cb4b0f72a4654070a58.js b/priv/static/static/js/11.2cb4b0f72a4654070a58.js
deleted file mode 100644
index 03b0234f2..000000000
Binary files a/priv/static/static/js/11.2cb4b0f72a4654070a58.js and /dev/null differ
diff --git a/priv/static/static/js/11.c5b938b4349f87567338.js b/priv/static/static/js/11.c5b938b4349f87567338.js
new file mode 100644
index 000000000..b97f69bf3
Binary files /dev/null and b/priv/static/static/js/11.c5b938b4349f87567338.js differ
diff --git a/priv/static/static/js/11.2cb4b0f72a4654070a58.js.map b/priv/static/static/js/11.c5b938b4349f87567338.js.map
similarity index 56%
rename from priv/static/static/js/11.2cb4b0f72a4654070a58.js.map
rename to priv/static/static/js/11.c5b938b4349f87567338.js.map
index b53e5e23a..5ccf83b1d 100644
Binary files a/priv/static/static/js/11.2cb4b0f72a4654070a58.js.map and b/priv/static/static/js/11.c5b938b4349f87567338.js.map differ
diff --git a/priv/static/static/js/12.500b3e4676dd47599a58.js b/priv/static/static/js/12.500b3e4676dd47599a58.js
deleted file mode 100644
index 52dfbde92..000000000
Binary files a/priv/static/static/js/12.500b3e4676dd47599a58.js and /dev/null differ
diff --git a/priv/static/static/js/12.ab82f9512fa85e78c114.js b/priv/static/static/js/12.ab82f9512fa85e78c114.js
new file mode 100644
index 000000000..100d72b33
Binary files /dev/null and b/priv/static/static/js/12.ab82f9512fa85e78c114.js differ
diff --git a/priv/static/static/js/12.500b3e4676dd47599a58.js.map b/priv/static/static/js/12.ab82f9512fa85e78c114.js.map
similarity index 56%
rename from priv/static/static/js/12.500b3e4676dd47599a58.js.map
rename to priv/static/static/js/12.ab82f9512fa85e78c114.js.map
index 700da90b0..23335ae23 100644
Binary files a/priv/static/static/js/12.500b3e4676dd47599a58.js.map and b/priv/static/static/js/12.ab82f9512fa85e78c114.js.map differ
diff --git a/priv/static/static/js/13.3ef79a2643680080d28f.js b/priv/static/static/js/13.3ef79a2643680080d28f.js
deleted file mode 100644
index 4070d1f3f..000000000
Binary files a/priv/static/static/js/13.3ef79a2643680080d28f.js and /dev/null differ
diff --git a/priv/static/static/js/13.40e59c5015d3307b94ad.js b/priv/static/static/js/13.40e59c5015d3307b94ad.js
new file mode 100644
index 000000000..2088bb6b7
Binary files /dev/null and b/priv/static/static/js/13.40e59c5015d3307b94ad.js differ
diff --git a/priv/static/static/js/13.3ef79a2643680080d28f.js.map b/priv/static/static/js/13.40e59c5015d3307b94ad.js.map
similarity index 56%
rename from priv/static/static/js/13.3ef79a2643680080d28f.js.map
rename to priv/static/static/js/13.40e59c5015d3307b94ad.js.map
index bb2f24e3a..3931b5ef9 100644
Binary files a/priv/static/static/js/13.3ef79a2643680080d28f.js.map and b/priv/static/static/js/13.40e59c5015d3307b94ad.js.map differ
diff --git a/priv/static/static/js/14.b7f6eb3ea71d2ac2bb41.js b/priv/static/static/js/14.b7f6eb3ea71d2ac2bb41.js
deleted file mode 100644
index 316ba1291..000000000
Binary files a/priv/static/static/js/14.b7f6eb3ea71d2ac2bb41.js and /dev/null differ
diff --git a/priv/static/static/js/14.b7f6eb3ea71d2ac2bb41.js.map b/priv/static/static/js/14.b7f6eb3ea71d2ac2bb41.js.map
deleted file mode 100644
index 07a26f298..000000000
Binary files a/priv/static/static/js/14.b7f6eb3ea71d2ac2bb41.js.map and /dev/null differ
diff --git a/priv/static/static/js/14.de791a47ee5249a526b1.js b/priv/static/static/js/14.de791a47ee5249a526b1.js
new file mode 100644
index 000000000..0e341275e
Binary files /dev/null and b/priv/static/static/js/14.de791a47ee5249a526b1.js differ
diff --git a/priv/static/static/js/14.de791a47ee5249a526b1.js.map b/priv/static/static/js/14.de791a47ee5249a526b1.js.map
new file mode 100644
index 000000000..4bef54546
Binary files /dev/null and b/priv/static/static/js/14.de791a47ee5249a526b1.js.map differ
diff --git a/priv/static/static/js/15.d814a29a970070494722.js b/priv/static/static/js/15.d814a29a970070494722.js
deleted file mode 100644
index 17eaf5218..000000000
Binary files a/priv/static/static/js/15.d814a29a970070494722.js and /dev/null differ
diff --git a/priv/static/static/js/15.d814a29a970070494722.js.map b/priv/static/static/js/15.d814a29a970070494722.js.map
deleted file mode 100644
index 9792088bf..000000000
Binary files a/priv/static/static/js/15.d814a29a970070494722.js.map and /dev/null differ
diff --git a/priv/static/static/js/15.e24854297ad682aec45a.js b/priv/static/static/js/15.e24854297ad682aec45a.js
new file mode 100644
index 000000000..671370192
Binary files /dev/null and b/priv/static/static/js/15.e24854297ad682aec45a.js differ
diff --git a/priv/static/static/js/15.e24854297ad682aec45a.js.map b/priv/static/static/js/15.e24854297ad682aec45a.js.map
new file mode 100644
index 000000000..89789a542
Binary files /dev/null and b/priv/static/static/js/15.e24854297ad682aec45a.js.map differ
diff --git a/priv/static/static/js/16.017fa510b293035ac370.js b/priv/static/static/js/16.017fa510b293035ac370.js
deleted file mode 100644
index 387cfc9c7..000000000
Binary files a/priv/static/static/js/16.017fa510b293035ac370.js and /dev/null differ
diff --git a/priv/static/static/js/16.017fa510b293035ac370.js.map b/priv/static/static/js/16.017fa510b293035ac370.js.map
deleted file mode 100644
index 2886028bd..000000000
Binary files a/priv/static/static/js/16.017fa510b293035ac370.js.map and /dev/null differ
diff --git a/priv/static/static/js/16.b7b0e4b8227a50fcb9bb.js b/priv/static/static/js/16.b7b0e4b8227a50fcb9bb.js
new file mode 100644
index 000000000..6a3ea9513
Binary files /dev/null and b/priv/static/static/js/16.b7b0e4b8227a50fcb9bb.js differ
diff --git a/priv/static/static/js/16.b7b0e4b8227a50fcb9bb.js.map b/priv/static/static/js/16.b7b0e4b8227a50fcb9bb.js.map
new file mode 100644
index 000000000..fec45b087
Binary files /dev/null and b/priv/static/static/js/16.b7b0e4b8227a50fcb9bb.js.map differ
diff --git a/priv/static/static/js/17.c63932b65417ee7346a3.js b/priv/static/static/js/17.c63932b65417ee7346a3.js
deleted file mode 100644
index e3172472a..000000000
Binary files a/priv/static/static/js/17.c63932b65417ee7346a3.js and /dev/null differ
diff --git a/priv/static/static/js/17.c63932b65417ee7346a3.js.map b/priv/static/static/js/17.c63932b65417ee7346a3.js.map
deleted file mode 100644
index f4c55d0cc..000000000
Binary files a/priv/static/static/js/17.c63932b65417ee7346a3.js.map and /dev/null differ
diff --git a/priv/static/static/js/17.c98118b6bb84ee3b5b08.js b/priv/static/static/js/17.c98118b6bb84ee3b5b08.js
new file mode 100644
index 000000000..c41f0b6b8
Binary files /dev/null and b/priv/static/static/js/17.c98118b6bb84ee3b5b08.js differ
diff --git a/priv/static/static/js/17.c98118b6bb84ee3b5b08.js.map b/priv/static/static/js/17.c98118b6bb84ee3b5b08.js.map
new file mode 100644
index 000000000..0c20fc89b
Binary files /dev/null and b/priv/static/static/js/17.c98118b6bb84ee3b5b08.js.map differ
diff --git a/priv/static/static/js/18.89c20aa67a4dd067ea37.js b/priv/static/static/js/18.89c20aa67a4dd067ea37.js
new file mode 100644
index 000000000..db1c78a49
Binary files /dev/null and b/priv/static/static/js/18.89c20aa67a4dd067ea37.js differ
diff --git a/priv/static/static/js/18.89c20aa67a4dd067ea37.js.map b/priv/static/static/js/18.89c20aa67a4dd067ea37.js.map
new file mode 100644
index 000000000..72cdf0e0e
Binary files /dev/null and b/priv/static/static/js/18.89c20aa67a4dd067ea37.js.map differ
diff --git a/priv/static/static/js/18.fd12f9746a55aa24a8b7.js b/priv/static/static/js/18.fd12f9746a55aa24a8b7.js
deleted file mode 100644
index be1ecbba5..000000000
Binary files a/priv/static/static/js/18.fd12f9746a55aa24a8b7.js and /dev/null differ
diff --git a/priv/static/static/js/18.fd12f9746a55aa24a8b7.js.map b/priv/static/static/js/18.fd12f9746a55aa24a8b7.js.map
deleted file mode 100644
index c98c107b3..000000000
Binary files a/priv/static/static/js/18.fd12f9746a55aa24a8b7.js.map and /dev/null differ
diff --git a/priv/static/static/js/19.3adebd64964c92700074.js b/priv/static/static/js/19.3adebd64964c92700074.js
deleted file mode 100644
index 9d5adbe4e..000000000
Binary files a/priv/static/static/js/19.3adebd64964c92700074.js and /dev/null differ
diff --git a/priv/static/static/js/19.3adebd64964c92700074.js.map b/priv/static/static/js/19.3adebd64964c92700074.js.map
deleted file mode 100644
index d113a66dc..000000000
Binary files a/priv/static/static/js/19.3adebd64964c92700074.js.map and /dev/null differ
diff --git a/priv/static/static/js/19.6e13bad8131c4501c1c5.js b/priv/static/static/js/19.6e13bad8131c4501c1c5.js
new file mode 100644
index 000000000..8b32827cc
Binary files /dev/null and b/priv/static/static/js/19.6e13bad8131c4501c1c5.js differ
diff --git a/priv/static/static/js/19.6e13bad8131c4501c1c5.js.map b/priv/static/static/js/19.6e13bad8131c4501c1c5.js.map
new file mode 100644
index 000000000..762d85e27
Binary files /dev/null and b/priv/static/static/js/19.6e13bad8131c4501c1c5.js.map differ
diff --git a/priv/static/static/js/2.78a48aa26599b00c3b8d.js b/priv/static/static/js/2.78a48aa26599b00c3b8d.js
new file mode 100644
index 000000000..ecb27aa9c
Binary files /dev/null and b/priv/static/static/js/2.78a48aa26599b00c3b8d.js differ
diff --git a/priv/static/static/js/2.78a48aa26599b00c3b8d.js.map b/priv/static/static/js/2.78a48aa26599b00c3b8d.js.map
new file mode 100644
index 000000000..167cfa1c6
Binary files /dev/null and b/priv/static/static/js/2.78a48aa26599b00c3b8d.js.map differ
diff --git a/priv/static/static/js/2.d81ca020d6885c6c3b03.js b/priv/static/static/js/2.d81ca020d6885c6c3b03.js
deleted file mode 100644
index f751a05da..000000000
Binary files a/priv/static/static/js/2.d81ca020d6885c6c3b03.js and /dev/null differ
diff --git a/priv/static/static/js/2.d81ca020d6885c6c3b03.js.map b/priv/static/static/js/2.d81ca020d6885c6c3b03.js.map
deleted file mode 100644
index 9a675dbc5..000000000
Binary files a/priv/static/static/js/2.d81ca020d6885c6c3b03.js.map and /dev/null differ
diff --git a/priv/static/static/js/20.3615c3cea2e1c2707a4f.js b/priv/static/static/js/20.3615c3cea2e1c2707a4f.js
new file mode 100644
index 000000000..74f89016c
Binary files /dev/null and b/priv/static/static/js/20.3615c3cea2e1c2707a4f.js differ
diff --git a/priv/static/static/js/20.3615c3cea2e1c2707a4f.js.map b/priv/static/static/js/20.3615c3cea2e1c2707a4f.js.map
new file mode 100644
index 000000000..acddecea7
Binary files /dev/null and b/priv/static/static/js/20.3615c3cea2e1c2707a4f.js.map differ
diff --git a/priv/static/static/js/20.e0c3ad29d59470506c04.js b/priv/static/static/js/20.e0c3ad29d59470506c04.js
deleted file mode 100644
index ddedbd1ff..000000000
Binary files a/priv/static/static/js/20.e0c3ad29d59470506c04.js and /dev/null differ
diff --git a/priv/static/static/js/20.e0c3ad29d59470506c04.js.map b/priv/static/static/js/20.e0c3ad29d59470506c04.js.map
deleted file mode 100644
index 83a9fbc98..000000000
Binary files a/priv/static/static/js/20.e0c3ad29d59470506c04.js.map and /dev/null differ
diff --git a/priv/static/static/js/21.64dedfc646e13e6f7915.js b/priv/static/static/js/21.64dedfc646e13e6f7915.js
new file mode 100644
index 000000000..407e6665e
Binary files /dev/null and b/priv/static/static/js/21.64dedfc646e13e6f7915.js differ
diff --git a/priv/static/static/js/21.64dedfc646e13e6f7915.js.map b/priv/static/static/js/21.64dedfc646e13e6f7915.js.map
new file mode 100644
index 000000000..8e3432668
Binary files /dev/null and b/priv/static/static/js/21.64dedfc646e13e6f7915.js.map differ
diff --git a/priv/static/static/js/21.849ecc09a1d58bdc64c6.js b/priv/static/static/js/21.849ecc09a1d58bdc64c6.js
deleted file mode 100644
index ef58a3da1..000000000
Binary files a/priv/static/static/js/21.849ecc09a1d58bdc64c6.js and /dev/null differ
diff --git a/priv/static/static/js/21.849ecc09a1d58bdc64c6.js.map b/priv/static/static/js/21.849ecc09a1d58bdc64c6.js.map
deleted file mode 100644
index 9447b7ce3..000000000
Binary files a/priv/static/static/js/21.849ecc09a1d58bdc64c6.js.map and /dev/null differ
diff --git a/priv/static/static/js/22.6fa63bc6a054b7638e9e.js b/priv/static/static/js/22.6fa63bc6a054b7638e9e.js
new file mode 100644
index 000000000..4a8740c99
Binary files /dev/null and b/priv/static/static/js/22.6fa63bc6a054b7638e9e.js differ
diff --git a/priv/static/static/js/22.6fa63bc6a054b7638e9e.js.map b/priv/static/static/js/22.6fa63bc6a054b7638e9e.js.map
new file mode 100644
index 000000000..1c556f040
Binary files /dev/null and b/priv/static/static/js/22.6fa63bc6a054b7638e9e.js.map differ
diff --git a/priv/static/static/js/22.8782f133c9f66d3f2bbe.js b/priv/static/static/js/22.8782f133c9f66d3f2bbe.js
deleted file mode 100644
index 82692acdb..000000000
Binary files a/priv/static/static/js/22.8782f133c9f66d3f2bbe.js and /dev/null differ
diff --git a/priv/static/static/js/22.8782f133c9f66d3f2bbe.js.map b/priv/static/static/js/22.8782f133c9f66d3f2bbe.js.map
deleted file mode 100644
index 41e527ff6..000000000
Binary files a/priv/static/static/js/22.8782f133c9f66d3f2bbe.js.map and /dev/null differ
diff --git a/priv/static/static/js/23.2653bf91bc77c2ed0160.js b/priv/static/static/js/23.2653bf91bc77c2ed0160.js
deleted file mode 100644
index 2aad331b4..000000000
Binary files a/priv/static/static/js/23.2653bf91bc77c2ed0160.js and /dev/null differ
diff --git a/priv/static/static/js/23.2653bf91bc77c2ed0160.js.map b/priv/static/static/js/23.2653bf91bc77c2ed0160.js.map
deleted file mode 100644
index 4f031922e..000000000
Binary files a/priv/static/static/js/23.2653bf91bc77c2ed0160.js.map and /dev/null differ
diff --git a/priv/static/static/js/23.e0ddea2b6e049d221ee7.js b/priv/static/static/js/23.e0ddea2b6e049d221ee7.js
new file mode 100644
index 000000000..51fe36368
Binary files /dev/null and b/priv/static/static/js/23.e0ddea2b6e049d221ee7.js differ
diff --git a/priv/static/static/js/23.e0ddea2b6e049d221ee7.js.map b/priv/static/static/js/23.e0ddea2b6e049d221ee7.js.map
new file mode 100644
index 000000000..36bae2bf4
Binary files /dev/null and b/priv/static/static/js/23.e0ddea2b6e049d221ee7.js.map differ
diff --git a/priv/static/static/js/24.38e3b9d44e9ee703ebf6.js b/priv/static/static/js/24.38e3b9d44e9ee703ebf6.js
new file mode 100644
index 000000000..e5abf0af6
Binary files /dev/null and b/priv/static/static/js/24.38e3b9d44e9ee703ebf6.js differ
diff --git a/priv/static/static/js/24.38e3b9d44e9ee703ebf6.js.map b/priv/static/static/js/24.38e3b9d44e9ee703ebf6.js.map
new file mode 100644
index 000000000..09f3c19d0
Binary files /dev/null and b/priv/static/static/js/24.38e3b9d44e9ee703ebf6.js.map differ
diff --git a/priv/static/static/js/24.f931d864a2297d880a9a.js b/priv/static/static/js/24.f931d864a2297d880a9a.js
deleted file mode 100644
index 0362730e0..000000000
Binary files a/priv/static/static/js/24.f931d864a2297d880a9a.js and /dev/null differ
diff --git a/priv/static/static/js/24.f931d864a2297d880a9a.js.map b/priv/static/static/js/24.f931d864a2297d880a9a.js.map
deleted file mode 100644
index 2fb375e79..000000000
Binary files a/priv/static/static/js/24.f931d864a2297d880a9a.js.map and /dev/null differ
diff --git a/priv/static/static/js/25.696b41c0a8660e1f85af.js b/priv/static/static/js/25.696b41c0a8660e1f85af.js
new file mode 100644
index 000000000..b114890fc
Binary files /dev/null and b/priv/static/static/js/25.696b41c0a8660e1f85af.js differ
diff --git a/priv/static/static/js/25.696b41c0a8660e1f85af.js.map b/priv/static/static/js/25.696b41c0a8660e1f85af.js.map
new file mode 100644
index 000000000..f6d208812
Binary files /dev/null and b/priv/static/static/js/25.696b41c0a8660e1f85af.js.map differ
diff --git a/priv/static/static/js/25.886acc9ba83c64659279.js b/priv/static/static/js/25.886acc9ba83c64659279.js
deleted file mode 100644
index 4ff4c331b..000000000
Binary files a/priv/static/static/js/25.886acc9ba83c64659279.js and /dev/null differ
diff --git a/priv/static/static/js/25.886acc9ba83c64659279.js.map b/priv/static/static/js/25.886acc9ba83c64659279.js.map
deleted file mode 100644
index c39f71238..000000000
Binary files a/priv/static/static/js/25.886acc9ba83c64659279.js.map and /dev/null differ
diff --git a/priv/static/static/js/26.1168f22384be75dc5492.js b/priv/static/static/js/26.1168f22384be75dc5492.js
new file mode 100644
index 000000000..b77a4d30f
Binary files /dev/null and b/priv/static/static/js/26.1168f22384be75dc5492.js differ
diff --git a/priv/static/static/js/26.1168f22384be75dc5492.js.map b/priv/static/static/js/26.1168f22384be75dc5492.js.map
new file mode 100644
index 000000000..c9b0d8495
Binary files /dev/null and b/priv/static/static/js/26.1168f22384be75dc5492.js.map differ
diff --git a/priv/static/static/js/26.e15b1645079c72c60586.js b/priv/static/static/js/26.e15b1645079c72c60586.js
deleted file mode 100644
index 303170088..000000000
Binary files a/priv/static/static/js/26.e15b1645079c72c60586.js and /dev/null differ
diff --git a/priv/static/static/js/26.e15b1645079c72c60586.js.map b/priv/static/static/js/26.e15b1645079c72c60586.js.map
deleted file mode 100644
index e62345884..000000000
Binary files a/priv/static/static/js/26.e15b1645079c72c60586.js.map and /dev/null differ
diff --git a/priv/static/static/js/27.3c0cfbb2a898b35486dd.js b/priv/static/static/js/27.3c0cfbb2a898b35486dd.js
new file mode 100644
index 000000000..a0765356f
Binary files /dev/null and b/priv/static/static/js/27.3c0cfbb2a898b35486dd.js differ
diff --git a/priv/static/static/js/27.3c0cfbb2a898b35486dd.js.map b/priv/static/static/js/27.3c0cfbb2a898b35486dd.js.map
new file mode 100644
index 000000000..0cc5f46b2
Binary files /dev/null and b/priv/static/static/js/27.3c0cfbb2a898b35486dd.js.map differ
diff --git a/priv/static/static/js/27.7b41e5953f74af7fddd1.js b/priv/static/static/js/27.7b41e5953f74af7fddd1.js
deleted file mode 100644
index 769fba11b..000000000
Binary files a/priv/static/static/js/27.7b41e5953f74af7fddd1.js and /dev/null differ
diff --git a/priv/static/static/js/27.7b41e5953f74af7fddd1.js.map b/priv/static/static/js/27.7b41e5953f74af7fddd1.js.map
deleted file mode 100644
index 078f5ff9a..000000000
Binary files a/priv/static/static/js/27.7b41e5953f74af7fddd1.js.map and /dev/null differ
diff --git a/priv/static/static/js/28.4f39e562aaceaa01e883.js b/priv/static/static/js/28.4f39e562aaceaa01e883.js
deleted file mode 100644
index 629359bda..000000000
Binary files a/priv/static/static/js/28.4f39e562aaceaa01e883.js and /dev/null differ
diff --git a/priv/static/static/js/28.4f39e562aaceaa01e883.js.map b/priv/static/static/js/28.4f39e562aaceaa01e883.js.map
deleted file mode 100644
index 24c675a4c..000000000
Binary files a/priv/static/static/js/28.4f39e562aaceaa01e883.js.map and /dev/null differ
diff --git a/priv/static/static/js/28.926c71d6f1813e177271.js b/priv/static/static/js/28.926c71d6f1813e177271.js
new file mode 100644
index 000000000..55cf840f2
Binary files /dev/null and b/priv/static/static/js/28.926c71d6f1813e177271.js differ
diff --git a/priv/static/static/js/28.926c71d6f1813e177271.js.map b/priv/static/static/js/28.926c71d6f1813e177271.js.map
new file mode 100644
index 000000000..1ae8f08cb
Binary files /dev/null and b/priv/static/static/js/28.926c71d6f1813e177271.js.map differ
diff --git a/priv/static/static/js/29.137e2a68b558eed58152.js b/priv/static/static/js/29.137e2a68b558eed58152.js
deleted file mode 100644
index 50cb11ffd..000000000
Binary files a/priv/static/static/js/29.137e2a68b558eed58152.js and /dev/null differ
diff --git a/priv/static/static/js/29.137e2a68b558eed58152.js.map b/priv/static/static/js/29.137e2a68b558eed58152.js.map
deleted file mode 100644
index 0ac2f7fd3..000000000
Binary files a/priv/static/static/js/29.137e2a68b558eed58152.js.map and /dev/null differ
diff --git a/priv/static/static/js/29.187064ebed099ae45749.js b/priv/static/static/js/29.187064ebed099ae45749.js
new file mode 100644
index 000000000..6eaae0226
Binary files /dev/null and b/priv/static/static/js/29.187064ebed099ae45749.js differ
diff --git a/priv/static/static/js/29.187064ebed099ae45749.js.map b/priv/static/static/js/29.187064ebed099ae45749.js.map
new file mode 100644
index 000000000..b5dd63f96
Binary files /dev/null and b/priv/static/static/js/29.187064ebed099ae45749.js.map differ
diff --git a/priv/static/static/js/30.73e09f3b43617410dec7.js b/priv/static/static/js/30.73e09f3b43617410dec7.js
deleted file mode 100644
index 0c3d03cfa..000000000
Binary files a/priv/static/static/js/30.73e09f3b43617410dec7.js and /dev/null differ
diff --git a/priv/static/static/js/30.73e09f3b43617410dec7.js.map b/priv/static/static/js/30.73e09f3b43617410dec7.js.map
deleted file mode 100644
index cb546de17..000000000
Binary files a/priv/static/static/js/30.73e09f3b43617410dec7.js.map and /dev/null differ
diff --git a/priv/static/static/js/30.d78855ca19bf749be905.js b/priv/static/static/js/30.d78855ca19bf749be905.js
new file mode 100644
index 000000000..9202d19d3
Binary files /dev/null and b/priv/static/static/js/30.d78855ca19bf749be905.js differ
diff --git a/priv/static/static/js/30.d78855ca19bf749be905.js.map b/priv/static/static/js/30.d78855ca19bf749be905.js.map
new file mode 100644
index 000000000..b9f39664d
Binary files /dev/null and b/priv/static/static/js/30.d78855ca19bf749be905.js.map differ
diff --git a/priv/static/static/js/5.2b4a2787bacdd3d910db.js b/priv/static/static/js/5.2b4a2787bacdd3d910db.js
deleted file mode 100644
index 18c059380..000000000
Binary files a/priv/static/static/js/5.2b4a2787bacdd3d910db.js and /dev/null differ
diff --git a/priv/static/static/js/5.84f3dce298bc720719c7.js b/priv/static/static/js/5.84f3dce298bc720719c7.js
new file mode 100644
index 000000000..242b2a525
Binary files /dev/null and b/priv/static/static/js/5.84f3dce298bc720719c7.js differ
diff --git a/priv/static/static/js/5.2b4a2787bacdd3d910db.js.map b/priv/static/static/js/5.84f3dce298bc720719c7.js.map
similarity index 57%
rename from priv/static/static/js/5.2b4a2787bacdd3d910db.js.map
rename to priv/static/static/js/5.84f3dce298bc720719c7.js.map
index e9e78632d..4fcc32982 100644
Binary files a/priv/static/static/js/5.2b4a2787bacdd3d910db.js.map and b/priv/static/static/js/5.84f3dce298bc720719c7.js.map differ
diff --git a/priv/static/static/js/6.9c94bc0cc78979694cf4.js b/priv/static/static/js/6.9c94bc0cc78979694cf4.js
deleted file mode 100644
index 415938f67..000000000
Binary files a/priv/static/static/js/6.9c94bc0cc78979694cf4.js and /dev/null differ
diff --git a/priv/static/static/js/6.b9497e1d403b901a664e.js b/priv/static/static/js/6.b9497e1d403b901a664e.js
new file mode 100644
index 000000000..8c66e9062
Binary files /dev/null and b/priv/static/static/js/6.b9497e1d403b901a664e.js differ
diff --git a/priv/static/static/js/6.9c94bc0cc78979694cf4.js.map b/priv/static/static/js/6.b9497e1d403b901a664e.js.map
similarity index 57%
rename from priv/static/static/js/6.9c94bc0cc78979694cf4.js.map
rename to priv/static/static/js/6.b9497e1d403b901a664e.js.map
index 948368f60..5af0576c7 100644
Binary files a/priv/static/static/js/6.9c94bc0cc78979694cf4.js.map and b/priv/static/static/js/6.b9497e1d403b901a664e.js.map differ
diff --git a/priv/static/static/js/7.455b574116ce3f004ffb.js b/priv/static/static/js/7.455b574116ce3f004ffb.js
new file mode 100644
index 000000000..0e35f6904
Binary files /dev/null and b/priv/static/static/js/7.455b574116ce3f004ffb.js differ
diff --git a/priv/static/static/js/7.b4ac57fd946a3a189047.js.map b/priv/static/static/js/7.455b574116ce3f004ffb.js.map
similarity index 57%
rename from priv/static/static/js/7.b4ac57fd946a3a189047.js.map
rename to priv/static/static/js/7.455b574116ce3f004ffb.js.map
index 054d52650..971b570e1 100644
Binary files a/priv/static/static/js/7.b4ac57fd946a3a189047.js.map and b/priv/static/static/js/7.455b574116ce3f004ffb.js.map differ
diff --git a/priv/static/static/js/7.b4ac57fd946a3a189047.js b/priv/static/static/js/7.b4ac57fd946a3a189047.js
deleted file mode 100644
index 18b6ab76c..000000000
Binary files a/priv/static/static/js/7.b4ac57fd946a3a189047.js and /dev/null differ
diff --git a/priv/static/static/js/8.8db9f2dcc5ed429777f7.js b/priv/static/static/js/8.8db9f2dcc5ed429777f7.js
new file mode 100644
index 000000000..79082fc7c
Binary files /dev/null and b/priv/static/static/js/8.8db9f2dcc5ed429777f7.js differ
diff --git a/priv/static/static/js/8.e03e32ca713d01db0433.js.map b/priv/static/static/js/8.8db9f2dcc5ed429777f7.js.map
similarity index 57%
rename from priv/static/static/js/8.e03e32ca713d01db0433.js.map
rename to priv/static/static/js/8.8db9f2dcc5ed429777f7.js.map
index d1385c203..e193375de 100644
Binary files a/priv/static/static/js/8.e03e32ca713d01db0433.js.map and b/priv/static/static/js/8.8db9f2dcc5ed429777f7.js.map differ
diff --git a/priv/static/static/js/8.e03e32ca713d01db0433.js b/priv/static/static/js/8.e03e32ca713d01db0433.js
deleted file mode 100644
index 4d5894322..000000000
Binary files a/priv/static/static/js/8.e03e32ca713d01db0433.js and /dev/null differ
diff --git a/priv/static/static/js/9.72d903ca8e0c5a532b87.js b/priv/static/static/js/9.72d903ca8e0c5a532b87.js
deleted file mode 100644
index ce0f066c5..000000000
Binary files a/priv/static/static/js/9.72d903ca8e0c5a532b87.js and /dev/null differ
diff --git a/priv/static/static/js/9.72d903ca8e0c5a532b87.js.map b/priv/static/static/js/9.72d903ca8e0c5a532b87.js.map
deleted file mode 100644
index 4cf79de5b..000000000
Binary files a/priv/static/static/js/9.72d903ca8e0c5a532b87.js.map and /dev/null differ
diff --git a/priv/static/static/js/9.da3973d058660aa9612f.js b/priv/static/static/js/9.da3973d058660aa9612f.js
new file mode 100644
index 000000000..50d977f67
Binary files /dev/null and b/priv/static/static/js/9.da3973d058660aa9612f.js differ
diff --git a/priv/static/static/js/9.da3973d058660aa9612f.js.map b/priv/static/static/js/9.da3973d058660aa9612f.js.map
new file mode 100644
index 000000000..4c8f70599
Binary files /dev/null and b/priv/static/static/js/9.da3973d058660aa9612f.js.map differ
diff --git a/priv/static/static/js/app.1e68e208590653dab5aa.js b/priv/static/static/js/app.1e68e208590653dab5aa.js
deleted file mode 100644
index 27cc3d910..000000000
Binary files a/priv/static/static/js/app.1e68e208590653dab5aa.js and /dev/null differ
diff --git a/priv/static/static/js/app.1e68e208590653dab5aa.js.map b/priv/static/static/js/app.1e68e208590653dab5aa.js.map
deleted file mode 100644
index 71636d936..000000000
Binary files a/priv/static/static/js/app.1e68e208590653dab5aa.js.map and /dev/null differ
diff --git a/priv/static/static/js/app.31bba9f1e242ff273dcb.js b/priv/static/static/js/app.31bba9f1e242ff273dcb.js
new file mode 100644
index 000000000..22413689c
Binary files /dev/null and b/priv/static/static/js/app.31bba9f1e242ff273dcb.js differ
diff --git a/priv/static/static/js/app.31bba9f1e242ff273dcb.js.map b/priv/static/static/js/app.31bba9f1e242ff273dcb.js.map
new file mode 100644
index 000000000..8ff7a00c6
Binary files /dev/null and b/priv/static/static/js/app.31bba9f1e242ff273dcb.js.map differ
diff --git a/priv/static/static/js/vendors~app.247dc52c7abe6a0dab87.js b/priv/static/static/js/vendors~app.9e24ed238da5a8538f50.js
similarity index 89%
rename from priv/static/static/js/vendors~app.247dc52c7abe6a0dab87.js
rename to priv/static/static/js/vendors~app.9e24ed238da5a8538f50.js
index bf6671e4b..76c8a8dc1 100644
Binary files a/priv/static/static/js/vendors~app.247dc52c7abe6a0dab87.js and b/priv/static/static/js/vendors~app.9e24ed238da5a8538f50.js differ
diff --git a/priv/static/static/js/vendors~app.247dc52c7abe6a0dab87.js.map b/priv/static/static/js/vendors~app.9e24ed238da5a8538f50.js.map
similarity index 96%
rename from priv/static/static/js/vendors~app.247dc52c7abe6a0dab87.js.map
rename to priv/static/static/js/vendors~app.9e24ed238da5a8538f50.js.map
index 2a3bf1b99..f3c067c15 100644
Binary files a/priv/static/static/js/vendors~app.247dc52c7abe6a0dab87.js.map and b/priv/static/static/js/vendors~app.9e24ed238da5a8538f50.js.map differ
diff --git a/priv/static/sw-pleroma.js b/priv/static/sw-pleroma.js
index 098f58d49..9b7d127fd 100644
Binary files a/priv/static/sw-pleroma.js and b/priv/static/sw-pleroma.js differ
diff --git a/test/application_requirements_test.exs b/test/application_requirements_test.exs
index 481cdfd73..21d24ddd0 100644
--- a/test/application_requirements_test.exs
+++ b/test/application_requirements_test.exs
@@ -9,6 +9,56 @@ defmodule Pleroma.ApplicationRequirementsTest do
alias Pleroma.Repo
+ describe "check_welcome_message_config!/1" do
+ setup do: clear_config([:welcome])
+ setup do: clear_config([Pleroma.Emails.Mailer])
+
+ test "raises if welcome email enabled but mail disabled" do
+ Pleroma.Config.put([:welcome, :email, :enabled], true)
+ Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
+
+ assert_raise Pleroma.ApplicationRequirements.VerifyError, "The mail disabled.", fn ->
+ capture_log(&Pleroma.ApplicationRequirements.verify!/0)
+ end
+ end
+ end
+
+ describe "check_confirmation_accounts!" do
+ setup_with_mocks([
+ {Pleroma.ApplicationRequirements, [:passthrough],
+ [
+ check_migrations_applied!: fn _ -> :ok end
+ ]}
+ ]) do
+ :ok
+ end
+
+ setup do: clear_config([:instance, :account_activation_required])
+
+ test "raises if account confirmation is required but mailer isn't enable" do
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+ Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
+
+ assert_raise Pleroma.ApplicationRequirements.VerifyError,
+ "Account activation enabled, but Mailer is disabled. Cannot send confirmation emails.",
+ fn ->
+ capture_log(&Pleroma.ApplicationRequirements.verify!/0)
+ end
+ end
+
+ test "doesn't do anything if account confirmation is disabled" do
+ Pleroma.Config.put([:instance, :account_activation_required], false)
+ Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
+ assert Pleroma.ApplicationRequirements.verify!() == :ok
+ end
+
+ test "doesn't do anything if account confirmation is required and mailer is enabled" do
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+ Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], true)
+ assert Pleroma.ApplicationRequirements.verify!() == :ok
+ end
+ end
+
describe "check_rum!" do
setup_with_mocks([
{Pleroma.ApplicationRequirements, [:passthrough],
diff --git a/test/emails/admin_email_test.exs b/test/emails/admin_email_test.exs
index 9082ae5a7..e24231e27 100644
--- a/test/emails/admin_email_test.exs
+++ b/test/emails/admin_email_test.exs
@@ -46,4 +46,24 @@ test "it works when the reporter is a remote user without email" do
assert res.to == [{to_user.name, to_user.email}]
assert res.from == {config[:name], config[:notify_email]}
end
+
+ test "new unapproved registration email" do
+ config = Pleroma.Config.get(:instance)
+ to_user = insert(:user)
+ account = insert(:user, registration_reason: "Plz let me in")
+
+ res = AdminEmail.new_unapproved_registration(to_user, account)
+
+ account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)
+
+ assert res.to == [{to_user.name, to_user.email}]
+ assert res.from == {config[:name], config[:notify_email]}
+ assert res.subject == "New account up for review on #{config[:name]} (@#{account.nickname})"
+
+ assert res.html_body == """
+
New account for review: @#{account.nickname}
+
Plz let me in
+
Visit AdminFE
+ """
+ end
end
diff --git a/test/formatter_test.exs b/test/formatter_test.exs
index bef5a2c28..f066bd50a 100644
--- a/test/formatter_test.exs
+++ b/test/formatter_test.exs
@@ -10,6 +10,7 @@ defmodule Pleroma.FormatterTest do
import Pleroma.Factory
setup_all do
+ clear_config(Pleroma.Formatter)
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
@@ -255,6 +256,36 @@ test "it can parse mentions and return the relevant users" do
assert {_text, ^expected_mentions, []} = Formatter.linkify(text)
end
+
+ test "it parses URL containing local mention" do
+ _user = insert(:user, %{nickname: "lain"})
+
+ text = "https://example.com/@lain"
+
+ expected = ~S(
https://example.com/@lain)
+
+ assert {^expected, [], []} = Formatter.linkify(text)
+ end
+
+ test "it correctly parses angry face D:< with mention" do
+ lain =
+ insert(:user, %{
+ nickname: "lain@lain.com",
+ ap_id: "https://lain.com/users/lain",
+ id: "9qrWmR0cKniB0YU0TA"
+ })
+
+ text = "@lain@lain.com D:<"
+
+ expected_text =
+ ~S(
@lain D:<)
+
+ expected_mentions = [
+ {"@lain@lain.com", lain}
+ ]
+
+ assert {^expected_text, ^expected_mentions, []} = Formatter.linkify(text)
+ end
end
describe ".parse_tags" do
diff --git a/test/gun/conneciton_pool_test.exs b/test/gun/conneciton_pool_test.exs
new file mode 100644
index 000000000..aea908fac
--- /dev/null
+++ b/test/gun/conneciton_pool_test.exs
@@ -0,0 +1,101 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Gun.ConnectionPoolTest do
+ use Pleroma.DataCase
+
+ import Mox
+ import ExUnit.CaptureLog
+ alias Pleroma.Config
+ alias Pleroma.Gun.ConnectionPool
+
+ defp gun_mock(_) do
+ Pleroma.GunMock
+ |> stub(:open, fn _, _, _ -> Task.start_link(fn -> Process.sleep(100) end) end)
+ |> stub(:await_up, fn _, _ -> {:ok, :http} end)
+ |> stub(:set_owner, fn _, _ -> :ok end)
+
+ :ok
+ end
+
+ setup :set_mox_from_context
+ setup :gun_mock
+
+ test "gives the same connection to 2 concurrent requests" do
+ Enum.map(
+ [
+ "http://www.korean-books.com.kp/KBMbooks/en/periodic/pictorial/20200530163914.pdf",
+ "http://www.korean-books.com.kp/KBMbooks/en/periodic/pictorial/20200528183427.pdf"
+ ],
+ fn uri ->
+ uri = URI.parse(uri)
+ task_parent = self()
+
+ Task.start_link(fn ->
+ {:ok, conn} = ConnectionPool.get_conn(uri, [])
+ ConnectionPool.release_conn(conn)
+ send(task_parent, conn)
+ end)
+ end
+ )
+
+ [pid, pid] =
+ for _ <- 1..2 do
+ receive do
+ pid -> pid
+ end
+ end
+ end
+
+ test "connection limit is respected with concurrent requests" do
+ clear_config([:connections_pool, :max_connections]) do
+ Config.put([:connections_pool, :max_connections], 1)
+ # The supervisor needs a reboot to apply the new config setting
+ Process.exit(Process.whereis(Pleroma.Gun.ConnectionPool.WorkerSupervisor), :kill)
+
+ on_exit(fn ->
+ Process.exit(Process.whereis(Pleroma.Gun.ConnectionPool.WorkerSupervisor), :kill)
+ end)
+ end
+
+ capture_log(fn ->
+ Enum.map(
+ [
+ "https://ninenines.eu/",
+ "https://youtu.be/PFGwMiDJKNY"
+ ],
+ fn uri ->
+ uri = URI.parse(uri)
+ task_parent = self()
+
+ Task.start_link(fn ->
+ result = ConnectionPool.get_conn(uri, [])
+ # Sleep so that we don't end up with a situation,
+ # where request from the second process gets processed
+ # only after the first process already released the connection
+ Process.sleep(50)
+
+ case result do
+ {:ok, pid} ->
+ ConnectionPool.release_conn(pid)
+
+ _ ->
+ nil
+ end
+
+ send(task_parent, result)
+ end)
+ end
+ )
+
+ [{:error, :pool_full}, {:ok, _pid}] =
+ for _ <- 1..2 do
+ receive do
+ result -> result
+ end
+ end
+ |> Enum.sort()
+ end)
+ end
+end
diff --git a/test/http/adapter_helper/gun_test.exs b/test/http/adapter_helper/gun_test.exs
index 2e961826e..80589c73d 100644
--- a/test/http/adapter_helper/gun_test.exs
+++ b/test/http/adapter_helper/gun_test.exs
@@ -9,24 +9,10 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do
import Mox
alias Pleroma.Config
- alias Pleroma.Gun.Conn
alias Pleroma.HTTP.AdapterHelper.Gun
- alias Pleroma.Pool.Connections
setup :verify_on_exit!
- defp gun_mock(_) do
- gun_mock()
- :ok
- end
-
- defp gun_mock do
- Pleroma.GunMock
- |> stub(:open, fn _, _, _ -> Task.start_link(fn -> Process.sleep(1000) end) end)
- |> stub(:await_up, fn _, _ -> {:ok, :http} end)
- |> stub(:set_owner, fn _, _ -> :ok end)
- end
-
describe "options/1" do
setup do: clear_config([:http, :adapter], a: 1, b: 2)
@@ -35,7 +21,6 @@ test "https url with default port" do
opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
- assert opts[:tls_opts][:log_level] == :warning
end
test "https ipv4 with default port" do
@@ -43,7 +28,6 @@ test "https ipv4 with default port" do
opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
- assert opts[:tls_opts][:log_level] == :warning
end
test "https ipv6 with default port" do
@@ -51,7 +35,6 @@ test "https ipv6 with default port" do
opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
- assert opts[:tls_opts][:log_level] == :warning
end
test "https url with non standart port" do
@@ -62,46 +45,12 @@ test "https url with non standart port" do
assert opts[:certificates_verification]
end
- test "get conn on next request" do
- gun_mock()
- level = Application.get_env(:logger, :level)
- Logger.configure(level: :debug)
- on_exit(fn -> Logger.configure(level: level) end)
- uri = URI.parse("http://some-domain2.com")
-
- opts = Gun.options(uri)
-
- assert opts[:conn] == nil
- assert opts[:close_conn] == nil
-
- Process.sleep(50)
- opts = Gun.options(uri)
-
- assert is_pid(opts[:conn])
- assert opts[:close_conn] == false
- end
-
test "merges with defaul http adapter config" do
defaults = Gun.options([receive_conn: false], URI.parse("https://example.com"))
assert Keyword.has_key?(defaults, :a)
assert Keyword.has_key?(defaults, :b)
end
- test "default ssl adapter opts with connection" do
- gun_mock()
- uri = URI.parse("https://some-domain.com")
-
- :ok = Conn.open(uri, :gun_connections)
-
- opts = Gun.options(uri)
-
- assert opts[:certificates_verification]
- refute opts[:tls_opts] == []
-
- assert opts[:close_conn] == false
- assert is_pid(opts[:conn])
- end
-
test "parses string proxy host & port" do
proxy = Config.get([:http, :proxy_url])
Config.put([:http, :proxy_url], "localhost:8123")
@@ -132,127 +81,4 @@ test "passed opts have more weight than defaults" do
assert opts[:proxy] == {'example.com', 4321}
end
end
-
- describe "options/1 with receive_conn parameter" do
- setup :gun_mock
-
- test "receive conn by default" do
- uri = URI.parse("http://another-domain.com")
- :ok = Conn.open(uri, :gun_connections)
-
- received_opts = Gun.options(uri)
- assert received_opts[:close_conn] == false
- assert is_pid(received_opts[:conn])
- end
-
- test "don't receive conn if receive_conn is false" do
- uri = URI.parse("http://another-domain.com")
- :ok = Conn.open(uri, :gun_connections)
-
- opts = [receive_conn: false]
- received_opts = Gun.options(opts, uri)
- assert received_opts[:close_conn] == nil
- assert received_opts[:conn] == nil
- end
- end
-
- describe "after_request/1" do
- setup :gun_mock
-
- test "body_as not chunks" do
- uri = URI.parse("http://some-domain.com")
- :ok = Conn.open(uri, :gun_connections)
- opts = Gun.options(uri)
- :ok = Gun.after_request(opts)
- conn = opts[:conn]
-
- assert %Connections{
- conns: %{
- "http:some-domain.com:80" => %Pleroma.Gun.Conn{
- conn: ^conn,
- conn_state: :idle,
- used_by: []
- }
- }
- } = Connections.get_state(:gun_connections)
- end
-
- test "body_as chunks" do
- uri = URI.parse("http://some-domain.com")
- :ok = Conn.open(uri, :gun_connections)
- opts = Gun.options([body_as: :chunks], uri)
- :ok = Gun.after_request(opts)
- conn = opts[:conn]
- self = self()
-
- assert %Connections{
- conns: %{
- "http:some-domain.com:80" => %Pleroma.Gun.Conn{
- conn: ^conn,
- conn_state: :active,
- used_by: [{^self, _}]
- }
- }
- } = Connections.get_state(:gun_connections)
- end
-
- test "with no connection" do
- uri = URI.parse("http://uniq-domain.com")
-
- :ok = Conn.open(uri, :gun_connections)
-
- opts = Gun.options([body_as: :chunks], uri)
- conn = opts[:conn]
- opts = Keyword.delete(opts, :conn)
- self = self()
-
- :ok = Gun.after_request(opts)
-
- assert %Connections{
- conns: %{
- "http:uniq-domain.com:80" => %Pleroma.Gun.Conn{
- conn: ^conn,
- conn_state: :active,
- used_by: [{^self, _}]
- }
- }
- } = Connections.get_state(:gun_connections)
- end
-
- test "with ipv4" do
- uri = URI.parse("http://127.0.0.1")
- :ok = Conn.open(uri, :gun_connections)
- opts = Gun.options(uri)
- :ok = Gun.after_request(opts)
- conn = opts[:conn]
-
- assert %Connections{
- conns: %{
- "http:127.0.0.1:80" => %Pleroma.Gun.Conn{
- conn: ^conn,
- conn_state: :idle,
- used_by: []
- }
- }
- } = Connections.get_state(:gun_connections)
- end
-
- test "with ipv6" do
- uri = URI.parse("http://[2a03:2880:f10c:83:face:b00c:0:25de]")
- :ok = Conn.open(uri, :gun_connections)
- opts = Gun.options(uri)
- :ok = Gun.after_request(opts)
- conn = opts[:conn]
-
- assert %Connections{
- conns: %{
- "http:2a03:2880:f10c:83:face:b00c:0:25de:80" => %Pleroma.Gun.Conn{
- conn: ^conn,
- conn_state: :idle,
- used_by: []
- }
- }
- } = Connections.get_state(:gun_connections)
- end
- end
end
diff --git a/test/http/connection_test.exs b/test/http/connection_test.exs
deleted file mode 100644
index 7c94a50b2..000000000
--- a/test/http/connection_test.exs
+++ /dev/null
@@ -1,135 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.HTTP.ConnectionTest do
- use ExUnit.Case
- use Pleroma.Tests.Helpers
-
- import ExUnit.CaptureLog
-
- alias Pleroma.Config
- alias Pleroma.HTTP.Connection
-
- describe "parse_host/1" do
- test "as atom to charlist" do
- assert Connection.parse_host(:localhost) == 'localhost'
- end
-
- test "as string to charlist" do
- assert Connection.parse_host("localhost.com") == 'localhost.com'
- end
-
- test "as string ip to tuple" do
- assert Connection.parse_host("127.0.0.1") == {127, 0, 0, 1}
- end
- end
-
- describe "parse_proxy/1" do
- test "ip with port" do
- assert Connection.parse_proxy("127.0.0.1:8123") == {:ok, {127, 0, 0, 1}, 8123}
- end
-
- test "host with port" do
- assert Connection.parse_proxy("localhost:8123") == {:ok, 'localhost', 8123}
- end
-
- test "as tuple" do
- assert Connection.parse_proxy({:socks4, :localhost, 9050}) ==
- {:ok, :socks4, 'localhost', 9050}
- end
-
- test "as tuple with string host" do
- assert Connection.parse_proxy({:socks5, "localhost", 9050}) ==
- {:ok, :socks5, 'localhost', 9050}
- end
- end
-
- describe "parse_proxy/1 errors" do
- test "ip without port" do
- capture_log(fn ->
- assert Connection.parse_proxy("127.0.0.1") == {:error, :invalid_proxy}
- end) =~ "parsing proxy fail \"127.0.0.1\""
- end
-
- test "host without port" do
- capture_log(fn ->
- assert Connection.parse_proxy("localhost") == {:error, :invalid_proxy}
- end) =~ "parsing proxy fail \"localhost\""
- end
-
- test "host with bad port" do
- capture_log(fn ->
- assert Connection.parse_proxy("localhost:port") == {:error, :invalid_proxy_port}
- end) =~ "parsing port in proxy fail \"localhost:port\""
- end
-
- test "ip with bad port" do
- capture_log(fn ->
- assert Connection.parse_proxy("127.0.0.1:15.9") == {:error, :invalid_proxy_port}
- end) =~ "parsing port in proxy fail \"127.0.0.1:15.9\""
- end
-
- test "as tuple without port" do
- capture_log(fn ->
- assert Connection.parse_proxy({:socks5, :localhost}) == {:error, :invalid_proxy}
- end) =~ "parsing proxy fail {:socks5, :localhost}"
- end
-
- test "with nil" do
- assert Connection.parse_proxy(nil) == nil
- end
- end
-
- describe "options/3" do
- setup do: clear_config([:http, :proxy_url])
-
- test "without proxy_url in config" do
- Config.delete([:http, :proxy_url])
-
- opts = Connection.options(%URI{})
- refute Keyword.has_key?(opts, :proxy)
- end
-
- test "parses string proxy host & port" do
- Config.put([:http, :proxy_url], "localhost:8123")
-
- opts = Connection.options(%URI{})
- assert opts[:proxy] == {'localhost', 8123}
- end
-
- test "parses tuple proxy scheme host and port" do
- Config.put([:http, :proxy_url], {:socks, 'localhost', 1234})
-
- opts = Connection.options(%URI{})
- assert opts[:proxy] == {:socks, 'localhost', 1234}
- end
-
- test "passed opts have more weight than defaults" do
- Config.put([:http, :proxy_url], {:socks5, 'localhost', 1234})
-
- opts = Connection.options(%URI{}, proxy: {'example.com', 4321})
-
- assert opts[:proxy] == {'example.com', 4321}
- end
- end
-
- describe "format_host/1" do
- test "with domain" do
- assert Connection.format_host("example.com") == 'example.com'
- end
-
- test "with idna domain" do
- assert Connection.format_host("ですexample.com") == 'xn--example-183fne.com'
- end
-
- test "with ipv4" do
- assert Connection.format_host("127.0.0.1") == '127.0.0.1'
- end
-
- test "with ipv6" do
- assert Connection.format_host("2a03:2880:f10c:83:face:b00c:0:25de") ==
- '2a03:2880:f10c:83:face:b00c:0:25de'
- end
- end
-end
diff --git a/test/migrations/20200716195806_autolinker_to_linkify_test.exs b/test/migrations/20200716195806_autolinker_to_linkify_test.exs
new file mode 100644
index 000000000..250d11c61
--- /dev/null
+++ b/test/migrations/20200716195806_autolinker_to_linkify_test.exs
@@ -0,0 +1,68 @@
+defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ import Pleroma.Tests.Helpers
+ alias Pleroma.ConfigDB
+
+ setup do: clear_config(Pleroma.Formatter)
+ setup_all do: require_migration("20200716195806_autolinker_to_linkify")
+
+ test "change/0 converts auto_linker opts for Pleroma.Formatter", %{migration: migration} do
+ autolinker_opts = [
+ extra: true,
+ validate_tld: true,
+ class: false,
+ strip_prefix: false,
+ new_window: false,
+ rel: "testing"
+ ]
+
+ insert(:config, group: :auto_linker, key: :opts, value: autolinker_opts)
+
+ migration.change()
+
+ assert nil == ConfigDB.get_by_params(%{group: :auto_linker, key: :opts})
+
+ %{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter})
+
+ assert new_opts == [
+ class: false,
+ extra: true,
+ new_window: false,
+ rel: "testing",
+ strip_prefix: false
+ ]
+
+ Pleroma.Config.put(Pleroma.Formatter, new_opts)
+ assert new_opts == Pleroma.Config.get(Pleroma.Formatter)
+
+ {text, _mentions, []} =
+ Pleroma.Formatter.linkify(
+ "https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\n\nOmg will COVID finally end Black Friday???"
+ )
+
+ assert text ==
+ "
https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\n\nOmg will COVID finally end Black Friday???"
+ end
+
+ test "transform_opts/1 returns a list of compatible opts", %{migration: migration} do
+ old_opts = [
+ extra: true,
+ validate_tld: true,
+ class: false,
+ strip_prefix: false,
+ new_window: false,
+ rel: "qqq"
+ ]
+
+ expected_opts = [
+ class: false,
+ extra: true,
+ new_window: false,
+ rel: "qqq",
+ strip_prefix: false
+ ]
+
+ assert migration.transform_opts(old_opts) == expected_opts
+ end
+end
diff --git a/test/migrations/20200722185515_fix_malformed_formatter_config_test.exs b/test/migrations/20200722185515_fix_malformed_formatter_config_test.exs
new file mode 100644
index 000000000..d3490478e
--- /dev/null
+++ b/test/migrations/20200722185515_fix_malformed_formatter_config_test.exs
@@ -0,0 +1,66 @@
+defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfigTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ import Pleroma.Tests.Helpers
+ alias Pleroma.ConfigDB
+
+ setup do: clear_config(Pleroma.Formatter)
+ setup_all do: require_migration("20200722185515_fix_malformed_formatter_config")
+
+ test "change/0 converts a map into a list", %{migration: migration} do
+ incorrect_opts = %{
+ class: false,
+ extra: true,
+ new_window: false,
+ rel: "F",
+ strip_prefix: false
+ }
+
+ insert(:config, group: :pleroma, key: Pleroma.Formatter, value: incorrect_opts)
+
+ assert :ok == migration.change()
+
+ %{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter})
+
+ assert new_opts == [
+ class: false,
+ extra: true,
+ new_window: false,
+ rel: "F",
+ strip_prefix: false
+ ]
+
+ Pleroma.Config.put(Pleroma.Formatter, new_opts)
+ assert new_opts == Pleroma.Config.get(Pleroma.Formatter)
+
+ {text, _mentions, []} =
+ Pleroma.Formatter.linkify(
+ "https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\n\nOmg will COVID finally end Black Friday???"
+ )
+
+ assert text ==
+ "
https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\n\nOmg will COVID finally end Black Friday???"
+ end
+
+ test "change/0 skips if Pleroma.Formatter config is already a list", %{migration: migration} do
+ opts = [
+ class: false,
+ extra: true,
+ new_window: false,
+ rel: "ugc",
+ strip_prefix: false
+ ]
+
+ insert(:config, group: :pleroma, key: Pleroma.Formatter, value: opts)
+
+ assert :skipped == migration.change()
+
+ %{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter})
+
+ assert new_opts == opts
+ end
+
+ test "change/0 skips if Pleroma.Formatter is empty", %{migration: migration} do
+ assert :skipped == migration.change()
+ end
+end
diff --git a/test/migrations/20200724133313_move_welcome_settings_test.exs b/test/migrations/20200724133313_move_welcome_settings_test.exs
new file mode 100644
index 000000000..739f24547
--- /dev/null
+++ b/test/migrations/20200724133313_move_welcome_settings_test.exs
@@ -0,0 +1,140 @@
+defmodule Pleroma.Repo.Migrations.MoveWelcomeSettingsTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ import Pleroma.Tests.Helpers
+ alias Pleroma.ConfigDB
+
+ setup_all do: require_migration("20200724133313_move_welcome_settings")
+
+ describe "up/0" do
+ test "converts welcome settings", %{migration: migration} do
+ insert(:config,
+ group: :pleroma,
+ key: :instance,
+ value: [
+ welcome_message: "Test message",
+ welcome_user_nickname: "jimm",
+ name: "Pleroma"
+ ]
+ )
+
+ migration.up()
+ instance_config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
+ welcome_config = ConfigDB.get_by_params(%{group: :pleroma, key: :welcome})
+
+ assert instance_config.value == [name: "Pleroma"]
+
+ assert welcome_config.value == [
+ direct_message: %{
+ enabled: true,
+ message: "Test message",
+ sender_nickname: "jimm"
+ },
+ email: %{
+ enabled: false,
+ html: "Welcome to <%= instance_name %>",
+ sender: nil,
+ subject: "Welcome to <%= instance_name %>",
+ text: "Welcome to <%= instance_name %>"
+ }
+ ]
+ end
+
+ test "does nothing when message empty", %{migration: migration} do
+ insert(:config,
+ group: :pleroma,
+ key: :instance,
+ value: [
+ welcome_message: "",
+ welcome_user_nickname: "jimm",
+ name: "Pleroma"
+ ]
+ )
+
+ migration.up()
+ instance_config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
+ refute ConfigDB.get_by_params(%{group: :pleroma, key: :welcome})
+ assert instance_config.value == [name: "Pleroma"]
+ end
+
+ test "does nothing when welcome_message not set", %{migration: migration} do
+ insert(:config,
+ group: :pleroma,
+ key: :instance,
+ value: [welcome_user_nickname: "jimm", name: "Pleroma"]
+ )
+
+ migration.up()
+ instance_config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
+ refute ConfigDB.get_by_params(%{group: :pleroma, key: :welcome})
+ assert instance_config.value == [name: "Pleroma"]
+ end
+ end
+
+ describe "down/0" do
+ test "revert new settings to old when instance setting not exists", %{migration: migration} do
+ insert(:config,
+ group: :pleroma,
+ key: :welcome,
+ value: [
+ direct_message: %{
+ enabled: true,
+ message: "Test message",
+ sender_nickname: "jimm"
+ },
+ email: %{
+ enabled: false,
+ html: "Welcome to <%= instance_name %>",
+ sender: nil,
+ subject: "Welcome to <%= instance_name %>",
+ text: "Welcome to <%= instance_name %>"
+ }
+ ]
+ )
+
+ migration.down()
+
+ refute ConfigDB.get_by_params(%{group: :pleroma, key: :welcome})
+ instance_config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
+
+ assert instance_config.value == [
+ welcome_user_nickname: "jimm",
+ welcome_message: "Test message"
+ ]
+ end
+
+ test "revert new settings to old when instance setting exists", %{migration: migration} do
+ insert(:config, group: :pleroma, key: :instance, value: [name: "Pleroma App"])
+
+ insert(:config,
+ group: :pleroma,
+ key: :welcome,
+ value: [
+ direct_message: %{
+ enabled: true,
+ message: "Test message",
+ sender_nickname: "jimm"
+ },
+ email: %{
+ enabled: false,
+ html: "Welcome to <%= instance_name %>",
+ sender: nil,
+ subject: "Welcome to <%= instance_name %>",
+ text: "Welcome to <%= instance_name %>"
+ }
+ ]
+ )
+
+ migration.down()
+
+ refute ConfigDB.get_by_params(%{group: :pleroma, key: :welcome})
+ instance_config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
+
+ assert instance_config.value == [
+ name: "Pleroma App",
+ welcome_user_nickname: "jimm",
+ welcome_message: "Test message"
+ ]
+ end
+ end
+end
diff --git a/test/notification_test.exs b/test/notification_test.exs
index 13e82ab2a..8243cfd34 100644
--- a/test/notification_test.exs
+++ b/test/notification_test.exs
@@ -246,49 +246,18 @@ test "it creates a notification for an activity from a muted thread" do
assert Notification.create_notification(activity, muter)
end
- test "it disables notifications from followers" do
- follower = insert(:user)
-
- followed =
- insert(:user, notification_settings: %Pleroma.User.NotificationSetting{followers: false})
-
- User.follow(follower, followed)
- {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
- refute Notification.create_notification(activity, followed)
- end
-
- test "it disables notifications from non-followers" do
+ test "it disables notifications from strangers" do
follower = insert(:user)
followed =
insert(:user,
- notification_settings: %Pleroma.User.NotificationSetting{non_followers: false}
+ notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
)
{:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
refute Notification.create_notification(activity, followed)
end
- test "it disables notifications from people the user follows" do
- follower =
- insert(:user, notification_settings: %Pleroma.User.NotificationSetting{follows: false})
-
- followed = insert(:user)
- User.follow(follower, followed)
- follower = Repo.get(User, follower.id)
- {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
- refute Notification.create_notification(activity, follower)
- end
-
- test "it disables notifications from people the user does not follow" do
- follower =
- insert(:user, notification_settings: %Pleroma.User.NotificationSetting{non_follows: false})
-
- followed = insert(:user)
- {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
- refute Notification.create_notification(activity, follower)
- end
-
test "it doesn't create a notification for user if he is the activity author" do
activity = insert(:note_activity)
author = User.get_cached_by_ap_id(activity.data["actor"])
diff --git a/test/pagination_test.exs b/test/pagination_test.exs
index 9165427ae..e526f23e8 100644
--- a/test/pagination_test.exs
+++ b/test/pagination_test.exs
@@ -54,6 +54,20 @@ test "paginates by min_id & limit", %{notes: notes} do
assert length(paginated) == 1
end
+
+ test "handles id gracefully", %{notes: notes} do
+ id = Enum.at(notes, 1).id |> Integer.to_string()
+
+ paginated =
+ Pagination.fetch_paginated(Object, %{
+ id: "9s99Hq44Cnv8PKBwWG",
+ max_id: id,
+ limit: 20,
+ offset: 0
+ })
+
+ assert length(paginated) == 1
+ end
end
describe "offset" do
diff --git a/test/plugs/frontend_static_test.exs b/test/plugs/frontend_static_test.exs
new file mode 100644
index 000000000..d11d91d78
--- /dev/null
+++ b/test/plugs/frontend_static_test.exs
@@ -0,0 +1,30 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.FrontendStaticPlugTest do
+ use Pleroma.Web.ConnCase
+
+ @dir "test/tmp/instance_static"
+
+ setup do
+ File.mkdir_p!(@dir)
+ on_exit(fn -> File.rm_rf(@dir) end)
+ end
+
+ setup do: clear_config([:instance, :static_dir], @dir)
+
+ test "overrides existing static files", %{conn: conn} do
+ name = "pelmora"
+ ref = "uguu"
+
+ clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
+ path = "#{@dir}/frontends/#{name}/#{ref}"
+
+ File.mkdir_p!(path)
+ File.write!("#{path}/index.html", "from frontend plug")
+
+ index = get(conn, "/")
+ assert html_response(index, 200) == "from frontend plug"
+ end
+end
diff --git a/test/plugs/instance_static_test.exs b/test/plugs/instance_static_test.exs
index be2613ad0..d42ba817e 100644
--- a/test/plugs/instance_static_test.exs
+++ b/test/plugs/instance_static_test.exs
@@ -2,7 +2,7 @@
# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.RuntimeStaticPlugTest do
+defmodule Pleroma.Web.InstanceStaticPlugTest do
use Pleroma.Web.ConnCase
@dir "test/tmp/instance_static"
@@ -24,6 +24,28 @@ test "overrides index" do
assert html_response(index, 200) == "hello world"
end
+ test "also overrides frontend files", %{conn: conn} do
+ name = "pelmora"
+ ref = "uguu"
+
+ clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
+
+ bundled_index = get(conn, "/")
+ refute html_response(bundled_index, 200) == "from frontend plug"
+
+ path = "#{@dir}/frontends/#{name}/#{ref}"
+ File.mkdir_p!(path)
+ File.write!("#{path}/index.html", "from frontend plug")
+
+ index = get(conn, "/")
+ assert html_response(index, 200) == "from frontend plug"
+
+ File.write!(@dir <> "/index.html", "from instance static")
+
+ index = get(conn, "/")
+ assert html_response(index, 200) == "from instance static"
+ end
+
test "overrides any file in static/static" do
bundled_index = get(build_conn(), "/static/terms-of-service.html")
diff --git a/test/pool/connections_test.exs b/test/pool/connections_test.exs
deleted file mode 100644
index aeda54875..000000000
--- a/test/pool/connections_test.exs
+++ /dev/null
@@ -1,760 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Pool.ConnectionsTest do
- use ExUnit.Case, async: true
- use Pleroma.Tests.Helpers
-
- import ExUnit.CaptureLog
- import Mox
-
- alias Pleroma.Gun.Conn
- alias Pleroma.GunMock
- alias Pleroma.Pool.Connections
-
- setup :verify_on_exit!
-
- setup_all do
- name = :test_connections
- {:ok, pid} = Connections.start_link({name, [checkin_timeout: 150]})
- {:ok, _} = Registry.start_link(keys: :unique, name: Pleroma.GunMock)
-
- on_exit(fn ->
- if Process.alive?(pid), do: GenServer.stop(name)
- end)
-
- {:ok, name: name}
- end
-
- defp open_mock(num \\ 1) do
- GunMock
- |> expect(:open, num, &start_and_register(&1, &2, &3))
- |> expect(:await_up, num, fn _, _ -> {:ok, :http} end)
- |> expect(:set_owner, num, fn _, _ -> :ok end)
- end
-
- defp connect_mock(mock) do
- mock
- |> expect(:connect, &connect(&1, &2))
- |> expect(:await, &await(&1, &2))
- end
-
- defp info_mock(mock), do: expect(mock, :info, &info(&1))
-
- defp start_and_register('gun-not-up.com', _, _), do: {:error, :timeout}
-
- defp start_and_register(host, port, _) do
- {:ok, pid} = Task.start_link(fn -> Process.sleep(1000) end)
-
- scheme =
- case port do
- 443 -> "https"
- _ -> "http"
- end
-
- Registry.register(GunMock, pid, %{
- origin_scheme: scheme,
- origin_host: host,
- origin_port: port
- })
-
- {:ok, pid}
- end
-
- defp info(pid) do
- [{_, info}] = Registry.lookup(GunMock, pid)
- info
- end
-
- defp connect(pid, _) do
- ref = make_ref()
- Registry.register(GunMock, ref, pid)
- ref
- end
-
- defp await(pid, ref) do
- [{_, ^pid}] = Registry.lookup(GunMock, ref)
- {:response, :fin, 200, []}
- end
-
- defp now, do: :os.system_time(:second)
-
- describe "alive?/2" do
- test "is alive", %{name: name} do
- assert Connections.alive?(name)
- end
-
- test "returns false if not started" do
- refute Connections.alive?(:some_random_name)
- end
- end
-
- test "opens connection and reuse it on next request", %{name: name} do
- open_mock()
- url = "http://some-domain.com"
- key = "http:some-domain.com:80"
- refute Connections.checkin(url, name)
- :ok = Conn.open(url, name)
-
- conn = Connections.checkin(url, name)
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- self = self()
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert conn == reused_conn
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}, {^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
-
- :ok = Connections.checkout(conn, self, name)
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
-
- :ok = Connections.checkout(conn, self, name)
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [],
- conn_state: :idle
- }
- }
- } = Connections.get_state(name)
- end
-
- test "reuse connection for idna domains", %{name: name} do
- open_mock()
- url = "http://ですsome-domain.com"
- refute Connections.checkin(url, name)
-
- :ok = Conn.open(url, name)
-
- conn = Connections.checkin(url, name)
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- self = self()
-
- %Connections{
- conns: %{
- "http:ですsome-domain.com:80" => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert conn == reused_conn
- end
-
- test "reuse for ipv4", %{name: name} do
- open_mock()
- url = "http://127.0.0.1"
-
- refute Connections.checkin(url, name)
-
- :ok = Conn.open(url, name)
-
- conn = Connections.checkin(url, name)
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- self = self()
-
- %Connections{
- conns: %{
- "http:127.0.0.1:80" => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert conn == reused_conn
-
- :ok = Connections.checkout(conn, self, name)
- :ok = Connections.checkout(reused_conn, self, name)
-
- %Connections{
- conns: %{
- "http:127.0.0.1:80" => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [],
- conn_state: :idle
- }
- }
- } = Connections.get_state(name)
- end
-
- test "reuse for ipv6", %{name: name} do
- open_mock()
- url = "http://[2a03:2880:f10c:83:face:b00c:0:25de]"
-
- refute Connections.checkin(url, name)
-
- :ok = Conn.open(url, name)
-
- conn = Connections.checkin(url, name)
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- self = self()
-
- %Connections{
- conns: %{
- "http:2a03:2880:f10c:83:face:b00c:0:25de:80" => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert conn == reused_conn
- end
-
- test "up and down ipv4", %{name: name} do
- open_mock()
- |> info_mock()
- |> allow(self(), name)
-
- self = self()
- url = "http://127.0.0.1"
- :ok = Conn.open(url, name)
- conn = Connections.checkin(url, name)
- send(name, {:gun_down, conn, nil, nil, nil})
- send(name, {:gun_up, conn, nil})
-
- %Connections{
- conns: %{
- "http:127.0.0.1:80" => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
- end
-
- test "up and down ipv6", %{name: name} do
- self = self()
-
- open_mock()
- |> info_mock()
- |> allow(self, name)
-
- url = "http://[2a03:2880:f10c:83:face:b00c:0:25de]"
- :ok = Conn.open(url, name)
- conn = Connections.checkin(url, name)
- send(name, {:gun_down, conn, nil, nil, nil})
- send(name, {:gun_up, conn, nil})
-
- %Connections{
- conns: %{
- "http:2a03:2880:f10c:83:face:b00c:0:25de:80" => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}],
- conn_state: :active
- }
- }
- } = Connections.get_state(name)
- end
-
- test "reuses connection based on protocol", %{name: name} do
- open_mock(2)
- http_url = "http://some-domain.com"
- http_key = "http:some-domain.com:80"
- https_url = "https://some-domain.com"
- https_key = "https:some-domain.com:443"
-
- refute Connections.checkin(http_url, name)
- :ok = Conn.open(http_url, name)
- conn = Connections.checkin(http_url, name)
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- refute Connections.checkin(https_url, name)
- :ok = Conn.open(https_url, name)
- https_conn = Connections.checkin(https_url, name)
-
- refute conn == https_conn
-
- reused_https = Connections.checkin(https_url, name)
-
- refute conn == reused_https
-
- assert reused_https == https_conn
-
- %Connections{
- conns: %{
- ^http_key => %Conn{
- conn: ^conn,
- gun_state: :up
- },
- ^https_key => %Conn{
- conn: ^https_conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
- end
-
- test "connection can't get up", %{name: name} do
- expect(GunMock, :open, &start_and_register(&1, &2, &3))
- url = "http://gun-not-up.com"
-
- assert capture_log(fn ->
- refute Conn.open(url, name)
- refute Connections.checkin(url, name)
- end) =~
- "Opening connection to http://gun-not-up.com failed with error {:error, :timeout}"
- end
-
- test "process gun_down message and then gun_up", %{name: name} do
- self = self()
-
- open_mock()
- |> info_mock()
- |> allow(self, name)
-
- url = "http://gun-down-and-up.com"
- key = "http:gun-down-and-up.com:80"
- :ok = Conn.open(url, name)
- conn = Connections.checkin(url, name)
-
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: ^conn,
- gun_state: :up,
- used_by: [{^self, _}]
- }
- }
- } = Connections.get_state(name)
-
- send(name, {:gun_down, conn, :http, nil, nil})
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: ^conn,
- gun_state: :down,
- used_by: [{^self, _}]
- }
- }
- } = Connections.get_state(name)
-
- send(name, {:gun_up, conn, :http})
-
- conn2 = Connections.checkin(url, name)
- assert conn == conn2
-
- assert is_pid(conn2)
- assert Process.alive?(conn2)
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: _,
- gun_state: :up,
- used_by: [{^self, _}, {^self, _}]
- }
- }
- } = Connections.get_state(name)
- end
-
- test "async processes get same conn for same domain", %{name: name} do
- open_mock()
- url = "http://some-domain.com"
- :ok = Conn.open(url, name)
-
- tasks =
- for _ <- 1..5 do
- Task.async(fn ->
- Connections.checkin(url, name)
- end)
- end
-
- tasks_with_results = Task.yield_many(tasks)
-
- results =
- Enum.map(tasks_with_results, fn {task, res} ->
- res || Task.shutdown(task, :brutal_kill)
- end)
-
- conns = for {:ok, value} <- results, do: value
-
- %Connections{
- conns: %{
- "http:some-domain.com:80" => %Conn{
- conn: conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- assert Enum.all?(conns, fn res -> res == conn end)
- end
-
- test "remove frequently used and idle", %{name: name} do
- open_mock(3)
- self = self()
- http_url = "http://some-domain.com"
- https_url = "https://some-domain.com"
- :ok = Conn.open(https_url, name)
- :ok = Conn.open(http_url, name)
-
- conn1 = Connections.checkin(https_url, name)
-
- [conn2 | _conns] =
- for _ <- 1..4 do
- Connections.checkin(http_url, name)
- end
-
- http_key = "http:some-domain.com:80"
-
- %Connections{
- conns: %{
- ^http_key => %Conn{
- conn: ^conn2,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}, {^self, _}, {^self, _}, {^self, _}]
- },
- "https:some-domain.com:443" => %Conn{
- conn: ^conn1,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}]
- }
- }
- } = Connections.get_state(name)
-
- :ok = Connections.checkout(conn1, self, name)
-
- another_url = "http://another-domain.com"
- :ok = Conn.open(another_url, name)
- conn = Connections.checkin(another_url, name)
-
- %Connections{
- conns: %{
- "http:another-domain.com:80" => %Conn{
- conn: ^conn,
- gun_state: :up
- },
- ^http_key => %Conn{
- conn: _,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
- end
-
- describe "with proxy" do
- test "as ip", %{name: name} do
- open_mock()
- |> connect_mock()
-
- url = "http://proxy-string.com"
- key = "http:proxy-string.com:80"
- :ok = Conn.open(url, name, proxy: {{127, 0, 0, 1}, 8123})
-
- conn = Connections.checkin(url, name)
-
- %Connections{
- conns: %{
- ^key => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert reused_conn == conn
- end
-
- test "as host", %{name: name} do
- open_mock()
- |> connect_mock()
-
- url = "http://proxy-tuple-atom.com"
- :ok = Conn.open(url, name, proxy: {'localhost', 9050})
- conn = Connections.checkin(url, name)
-
- %Connections{
- conns: %{
- "http:proxy-tuple-atom.com:80" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert reused_conn == conn
- end
-
- test "as ip and ssl", %{name: name} do
- open_mock()
- |> connect_mock()
-
- url = "https://proxy-string.com"
-
- :ok = Conn.open(url, name, proxy: {{127, 0, 0, 1}, 8123})
- conn = Connections.checkin(url, name)
-
- %Connections{
- conns: %{
- "https:proxy-string.com:443" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert reused_conn == conn
- end
-
- test "as host and ssl", %{name: name} do
- open_mock()
- |> connect_mock()
-
- url = "https://proxy-tuple-atom.com"
- :ok = Conn.open(url, name, proxy: {'localhost', 9050})
- conn = Connections.checkin(url, name)
-
- %Connections{
- conns: %{
- "https:proxy-tuple-atom.com:443" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert reused_conn == conn
- end
-
- test "with socks type", %{name: name} do
- open_mock()
-
- url = "http://proxy-socks.com"
-
- :ok = Conn.open(url, name, proxy: {:socks5, 'localhost', 1234})
-
- conn = Connections.checkin(url, name)
-
- %Connections{
- conns: %{
- "http:proxy-socks.com:80" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert reused_conn == conn
- end
-
- test "with socks4 type and ssl", %{name: name} do
- open_mock()
- url = "https://proxy-socks.com"
-
- :ok = Conn.open(url, name, proxy: {:socks4, 'localhost', 1234})
-
- conn = Connections.checkin(url, name)
-
- %Connections{
- conns: %{
- "https:proxy-socks.com:443" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- reused_conn = Connections.checkin(url, name)
-
- assert reused_conn == conn
- end
- end
-
- describe "crf/3" do
- setup do
- crf = Connections.crf(1, 10, 1)
- {:ok, crf: crf}
- end
-
- test "more used will have crf higher", %{crf: crf} do
- # used 3 times
- crf1 = Connections.crf(1, 10, crf)
- crf1 = Connections.crf(1, 10, crf1)
-
- # used 2 times
- crf2 = Connections.crf(1, 10, crf)
-
- assert crf1 > crf2
- end
-
- test "recently used will have crf higher on equal references", %{crf: crf} do
- # used 3 sec ago
- crf1 = Connections.crf(3, 10, crf)
-
- # used 4 sec ago
- crf2 = Connections.crf(4, 10, crf)
-
- assert crf1 > crf2
- end
-
- test "equal crf on equal reference and time", %{crf: crf} do
- # used 2 times
- crf1 = Connections.crf(1, 10, crf)
-
- # used 2 times
- crf2 = Connections.crf(1, 10, crf)
-
- assert crf1 == crf2
- end
-
- test "recently used will have higher crf", %{crf: crf} do
- crf1 = Connections.crf(2, 10, crf)
- crf1 = Connections.crf(1, 10, crf1)
-
- crf2 = Connections.crf(3, 10, crf)
- crf2 = Connections.crf(4, 10, crf2)
- assert crf1 > crf2
- end
- end
-
- describe "get_unused_conns/1" do
- test "crf is equalent, sorting by reference", %{name: name} do
- Connections.add_conn(name, "1", %Conn{
- conn_state: :idle,
- last_reference: now() - 1
- })
-
- Connections.add_conn(name, "2", %Conn{
- conn_state: :idle,
- last_reference: now()
- })
-
- assert [{"1", _unused_conn} | _others] = Connections.get_unused_conns(name)
- end
-
- test "reference is equalent, sorting by crf", %{name: name} do
- Connections.add_conn(name, "1", %Conn{
- conn_state: :idle,
- crf: 1.999
- })
-
- Connections.add_conn(name, "2", %Conn{
- conn_state: :idle,
- crf: 2
- })
-
- assert [{"1", _unused_conn} | _others] = Connections.get_unused_conns(name)
- end
-
- test "higher crf and lower reference", %{name: name} do
- Connections.add_conn(name, "1", %Conn{
- conn_state: :idle,
- crf: 3,
- last_reference: now() - 1
- })
-
- Connections.add_conn(name, "2", %Conn{
- conn_state: :idle,
- crf: 2,
- last_reference: now()
- })
-
- assert [{"2", _unused_conn} | _others] = Connections.get_unused_conns(name)
- end
-
- test "lower crf and lower reference", %{name: name} do
- Connections.add_conn(name, "1", %Conn{
- conn_state: :idle,
- crf: 1.99,
- last_reference: now() - 1
- })
-
- Connections.add_conn(name, "2", %Conn{
- conn_state: :idle,
- crf: 2,
- last_reference: now()
- })
-
- assert [{"1", _unused_conn} | _others] = Connections.get_unused_conns(name)
- end
- end
-
- test "count/1" do
- name = :test_count
- {:ok, _} = Connections.start_link({name, [checkin_timeout: 150]})
- assert Connections.count(name) == 0
- Connections.add_conn(name, "1", %Conn{conn: self()})
- assert Connections.count(name) == 1
- Connections.remove_conn(name, "1")
- assert Connections.count(name) == 0
- end
-end
diff --git a/test/support/helpers.ex b/test/support/helpers.ex
index 26281b45e..5cbf2e291 100644
--- a/test/support/helpers.ex
+++ b/test/support/helpers.ex
@@ -32,6 +32,11 @@ defmacro clear_config(config_path, temp_setting) do
end
end
+ def require_migration(migration_name) do
+ [{module, _}] = Code.require_file("#{migration_name}.exs", "priv/repo/migrations")
+ {:ok, %{migration: module}}
+ end
+
defmacro __using__(_opts) do
quote do
import Pleroma.Tests.Helpers,
diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs
index 71f36c0e3..fb12e7fb3 100644
--- a/test/tasks/config_test.exs
+++ b/test/tasks/config_test.exs
@@ -129,8 +129,6 @@ test "load a settings with large values and pass to file", %{temp_file: temp_fil
autofollowed_nicknames: [],
max_pinned_statuses: 1,
attachment_links: false,
- welcome_user_nickname: nil,
- welcome_message: nil,
max_report_comment_size: 1000,
safe_dm_mentions: false,
healthcheck: false,
@@ -172,7 +170,7 @@ test "load a settings with large values and pass to file", %{temp_file: temp_fil
end
assert file ==
- "#{header}\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n welcome_user_nickname: nil,\n welcome_message: nil,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n"
+ "#{header}\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n"
end
end
end
diff --git a/test/tasks/release_env_test.exs b/test/tasks/release_env_test.exs
new file mode 100644
index 000000000..519f1eba9
--- /dev/null
+++ b/test/tasks/release_env_test.exs
@@ -0,0 +1,30 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Mix.Tasks.Pleroma.ReleaseEnvTest do
+ use ExUnit.Case
+ import ExUnit.CaptureIO, only: [capture_io: 1]
+
+ @path "config/pleroma.test.env"
+
+ def do_clean do
+ if File.exists?(@path) do
+ File.rm_rf(@path)
+ end
+ end
+
+ setup do
+ do_clean()
+ on_exit(fn -> do_clean() end)
+ :ok
+ end
+
+ test "generate pleroma.env" do
+ assert capture_io(fn ->
+ Mix.Tasks.Pleroma.ReleaseEnv.run(["gen", "--path", @path, "--force"])
+ end) =~ "The file generated"
+
+ assert File.read!(@path) =~ "RELEASE_COOKIE="
+ end
+end
diff --git a/test/upload/filter/anonymize_filename_test.exs b/test/upload/filter/anonymize_filename_test.exs
index 2d5c580f1..adff70f57 100644
--- a/test/upload/filter/anonymize_filename_test.exs
+++ b/test/upload/filter/anonymize_filename_test.exs
@@ -9,6 +9,8 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do
alias Pleroma.Upload
setup do
+ File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
+
upload_file = %Upload{
name: "an… image.jpg",
content_type: "image/jpg",
diff --git a/test/uploaders/local_test.exs b/test/uploaders/local_test.exs
index ae2cfef94..18122ff6c 100644
--- a/test/uploaders/local_test.exs
+++ b/test/uploaders/local_test.exs
@@ -14,6 +14,7 @@ test "it returns path to local folder for files" do
describe "put_file/1" do
test "put file to local folder" do
+ File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file_path = "local_upload/files/image.jpg"
file = %Pleroma.Upload{
@@ -32,6 +33,7 @@ test "put file to local folder" do
describe "delete_file/1" do
test "deletes local file" do
+ File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file_path = "local_upload/files/image.jpg"
file = %Pleroma.Upload{
diff --git a/test/user/notification_setting_test.exs b/test/user/notification_setting_test.exs
index 95bca22c4..308da216a 100644
--- a/test/user/notification_setting_test.exs
+++ b/test/user/notification_setting_test.exs
@@ -8,11 +8,11 @@ defmodule Pleroma.User.NotificationSettingTest do
alias Pleroma.User.NotificationSetting
describe "changeset/2" do
- test "sets valid privacy option" do
+ test "sets option to hide notification contents" do
changeset =
NotificationSetting.changeset(
%NotificationSetting{},
- %{"privacy_option" => true}
+ %{"hide_notification_contents" => true}
)
assert %Ecto.Changeset{valid?: true} = changeset
diff --git a/test/user/welcome_email_test.exs b/test/user/welcome_email_test.exs
new file mode 100644
index 000000000..d005d11b2
--- /dev/null
+++ b/test/user/welcome_email_test.exs
@@ -0,0 +1,61 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.WelcomeEmailTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Config
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User.WelcomeEmail
+
+ import Pleroma.Factory
+ import Swoosh.TestAssertions
+
+ setup do: clear_config([:welcome])
+
+ describe "send_email/1" do
+ test "send a welcome email" do
+ user = insert(:user, name: "Jimm")
+
+ Config.put([:welcome, :email, :enabled], true)
+ Config.put([:welcome, :email, :sender], "welcome@pleroma.app")
+
+ Config.put(
+ [:welcome, :email, :subject],
+ "Hello, welcome to pleroma: <%= instance_name %>"
+ )
+
+ Config.put(
+ [:welcome, :email, :html],
+ "
Hello <%= user.name %>.
Welcome to <%= instance_name %>
"
+ )
+
+ instance_name = Config.get([:instance, :name])
+
+ {:ok, _job} = WelcomeEmail.send_email(user)
+
+ ObanHelpers.perform_all()
+
+ assert_email_sent(
+ from: {instance_name, "welcome@pleroma.app"},
+ to: {user.name, user.email},
+ subject: "Hello, welcome to pleroma: #{instance_name}",
+ html_body: "
Hello #{user.name}.
Welcome to #{instance_name}
"
+ )
+
+ Config.put([:welcome, :email, :sender], {"Pleroma App", "welcome@pleroma.app"})
+
+ {:ok, _job} = WelcomeEmail.send_email(user)
+
+ ObanHelpers.perform_all()
+
+ assert_email_sent(
+ from: {"Pleroma App", "welcome@pleroma.app"},
+ to: {user.name, user.email},
+ subject: "Hello, welcome to pleroma: #{instance_name}",
+ html_body: "
Hello #{user.name}.
Welcome to #{instance_name}
"
+ )
+ end
+ end
+end
diff --git a/test/user/welcome_message_test.exs b/test/user/welcome_message_test.exs
new file mode 100644
index 000000000..3cd6f5cb7
--- /dev/null
+++ b/test/user/welcome_message_test.exs
@@ -0,0 +1,34 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.WelcomeMessageTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Config
+ alias Pleroma.User.WelcomeMessage
+
+ import Pleroma.Factory
+
+ setup do: clear_config([:welcome])
+
+ describe "post_message/1" do
+ test "send a direct welcome message" do
+ welcome_user = insert(:user)
+ user = insert(:user, name: "Jimm")
+
+ Config.put([:welcome, :direct_message, :enabled], true)
+ Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
+
+ Config.put(
+ [:welcome, :direct_message, :message],
+ "Hello. Welcome to Pleroma"
+ )
+
+ {:ok, %Pleroma.Activity{} = activity} = WelcomeMessage.post_message(user)
+ assert user.ap_id in activity.recipients
+ assert activity.data["directMessage"] == true
+ assert Pleroma.Object.normalize(activity).data["content"] =~ "Hello. Welcome to Pleroma"
+ end
+ end
+end
diff --git a/test/user_test.exs b/test/user_test.exs
index 9788e09d9..624baf8ad 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -17,6 +17,7 @@ defmodule Pleroma.UserTest do
import Pleroma.Factory
import ExUnit.CaptureLog
+ import Swoosh.TestAssertions
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -385,9 +386,10 @@ test "fetches correct profile for nickname beginning with number" do
password_confirmation: "test",
email: "email@example.com"
}
+
setup do: clear_config([:instance, :autofollowed_nicknames])
- setup do: clear_config([:instance, :welcome_message])
- setup do: clear_config([:instance, :welcome_user_nickname])
+ setup do: clear_config([:welcome])
+ setup do: clear_config([:instance, :account_activation_required])
test "it autofollows accounts that are set for it" do
user = insert(:user)
@@ -408,20 +410,45 @@ test "it autofollows accounts that are set for it" do
test "it sends a welcome message if it is set" do
welcome_user = insert(:user)
+ Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
+ Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
+ Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a cool site")
- Pleroma.Config.put([:instance, :welcome_user_nickname], welcome_user.nickname)
- Pleroma.Config.put([:instance, :welcome_message], "Hello, this is a cool site")
+ Pleroma.Config.put([:welcome, :email, :enabled], true)
+ Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
+
+ Pleroma.Config.put(
+ [:welcome, :email, :subject],
+ "Hello, welcome to cool site: <%= instance_name %>"
+ )
+
+ instance_name = Pleroma.Config.get([:instance, :name])
cng = User.register_changeset(%User{}, @full_user_data)
{:ok, registered_user} = User.register(cng)
+ ObanHelpers.perform_all()
activity = Repo.one(Pleroma.Activity)
assert registered_user.ap_id in activity.recipients
assert Object.normalize(activity).data["content"] =~ "cool site"
assert activity.actor == welcome_user.ap_id
+
+ assert_email_sent(
+ from: {instance_name, welcome_user.email},
+ to: {registered_user.name, registered_user.email},
+ subject: "Hello, welcome to cool site: #{instance_name}",
+ html_body: "Welcome to #{instance_name}"
+ )
end
- setup do: clear_config([:instance, :account_activation_required])
+ test "it sends a confirm email" do
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+
+ cng = User.register_changeset(%User{}, @full_user_data)
+ {:ok, registered_user} = User.register(cng)
+ ObanHelpers.perform_all()
+ assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
+ end
test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
Pleroma.Config.put([:instance, :account_activation_required], true)
@@ -516,6 +543,46 @@ test "it creates confirmed user if :confirmed option is given" do
end
end
+ describe "user registration, with :account_approval_required" do
+ @full_user_data %{
+ bio: "A guy",
+ name: "my name",
+ nickname: "nick",
+ password: "test",
+ password_confirmation: "test",
+ email: "email@example.com",
+ registration_reason: "I'm a cool guy :)"
+ }
+ setup do: clear_config([:instance, :account_approval_required], true)
+
+ test "it creates unapproved user" do
+ changeset = User.register_changeset(%User{}, @full_user_data)
+ assert changeset.valid?
+
+ {:ok, user} = Repo.insert(changeset)
+
+ assert user.approval_pending
+ assert user.registration_reason == "I'm a cool guy :)"
+ end
+
+ test "it restricts length of registration reason" do
+ reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
+
+ assert is_integer(reason_limit)
+
+ params =
+ @full_user_data
+ |> Map.put(
+ :registration_reason,
+ "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
+ )
+
+ changeset = User.register_changeset(%User{}, params)
+
+ refute changeset.valid?
+ end
+ end
+
describe "get_or_fetch/1" do
test "gets an existing user by nickname" do
user = insert(:user)
@@ -1181,6 +1248,31 @@ test "hide a user's statuses from timelines and notifications" do
end
end
+ describe "approve" do
+ test "approves a user" do
+ user = insert(:user, approval_pending: true)
+ assert true == user.approval_pending
+ {:ok, user} = User.approve(user)
+ assert false == user.approval_pending
+ end
+
+ test "approves a list of users" do
+ unapproved_users = [
+ insert(:user, approval_pending: true),
+ insert(:user, approval_pending: true),
+ insert(:user, approval_pending: true)
+ ]
+
+ {:ok, users} = User.approve(unapproved_users)
+
+ assert Enum.count(users) == 3
+
+ Enum.each(users, fn user ->
+ assert false == user.approval_pending
+ end)
+ end
+ end
+
describe "delete" do
setup do
{:ok, user} = insert(:user) |> User.set_cache()
@@ -1268,6 +1360,17 @@ test "deactivates user when activation is not required", %{user: user} do
end
end
+ test "delete/1 when approval is pending deletes the user" do
+ user = insert(:user, approval_pending: true)
+ {:ok, user: user}
+
+ {:ok, job} = User.delete(user)
+ {:ok, _} = ObanHelpers.perform(job)
+
+ refute User.get_cached_by_id(user.id)
+ refute User.get_by_id(user.id)
+ end
+
test "get_public_key_for_ap_id fetches a user that's not in the db" do
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
end
@@ -1342,6 +1445,14 @@ test "returns :deactivated for deactivated user" do
user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
assert User.account_status(user) == :deactivated
end
+
+ test "returns :approval_pending for unapproved user" do
+ user = insert(:user, local: true, approval_pending: true)
+ assert User.account_status(user) == :approval_pending
+
+ user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
+ assert User.account_status(user) == :approval_pending
+ end
end
describe "superuser?/1" do
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs
index e722f7c04..ed900d8f8 100644
--- a/test/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/web/activity_pub/activity_pub_controller_test.exs
@@ -1082,6 +1082,45 @@ test "it increases like count when receiving a like action", %{conn: conn} do
assert object = Object.get_by_ap_id(note_object.data["id"])
assert object.data["like_count"] == 1
end
+
+ test "it doesn't spreads faulty attributedTo or actor fields", %{
+ conn: conn,
+ activity: activity
+ } do
+ reimu = insert(:user, nickname: "reimu")
+ cirno = insert(:user, nickname: "cirno")
+
+ assert reimu.ap_id
+ assert cirno.ap_id
+
+ activity =
+ activity
+ |> put_in(["object", "actor"], reimu.ap_id)
+ |> put_in(["object", "attributedTo"], reimu.ap_id)
+ |> put_in(["actor"], reimu.ap_id)
+ |> put_in(["attributedTo"], reimu.ap_id)
+
+ _reimu_outbox =
+ conn
+ |> assign(:user, cirno)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/users/#{reimu.nickname}/outbox", activity)
+ |> json_response(403)
+
+ cirno_outbox =
+ conn
+ |> assign(:user, cirno)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/users/#{cirno.nickname}/outbox", activity)
+ |> json_response(201)
+
+ assert cirno_outbox["attributedTo"] == nil
+ assert cirno_outbox["actor"] == cirno.ap_id
+
+ assert cirno_object = Object.normalize(cirno_outbox["object"])
+ assert cirno_object.data["actor"] == cirno.ap_id
+ assert cirno_object.data["attributedTo"] == cirno.ap_id
+ end
end
describe "/relay/followers" do
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index f3951462f..d6eab7337 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -1179,7 +1179,8 @@ test "it can create a Flag activity",
"id" => activity_ap_id,
"content" => content,
"published" => activity_with_object.object.data["published"],
- "actor" => AccountView.render("show.json", %{user: target_account})
+ "actor" =>
+ AccountView.render("show.json", %{user: target_account, skip_visibility_check: true})
}
assert %Activity{
diff --git a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs b/test/web/activity_pub/mrf/anti_followbot_policy_test.exs
index fca0de7c6..3c795f5ac 100644
--- a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs
+++ b/test/web/activity_pub/mrf/anti_followbot_policy_test.exs
@@ -21,7 +21,7 @@ test "matches followbots by nickname" do
"id" => "https://example.com/activities/1234"
}
- {:reject, nil} = AntiFollowbotPolicy.filter(message)
+ assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
end
test "matches followbots by display name" do
@@ -36,7 +36,7 @@ test "matches followbots by display name" do
"id" => "https://example.com/activities/1234"
}
- {:reject, nil} = AntiFollowbotPolicy.filter(message)
+ assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
end
end
diff --git a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs b/test/web/activity_pub/mrf/ensure_re_prepended_test.exs
index 38ddec5bb..9a283f27d 100644
--- a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs
+++ b/test/web/activity_pub/mrf/ensure_re_prepended_test.exs
@@ -78,5 +78,15 @@ test "it skip if parent and child summary isn't equal" do
assert {:ok, res} = EnsureRePrepended.filter(message)
assert res == message
end
+
+ test "it skips if the object is only a reference" do
+ message = %{
+ "type" => "Create",
+ "object" => "somereference"
+ }
+
+ assert {:ok, res} = EnsureRePrepended.filter(message)
+ assert res == message
+ end
end
end
diff --git a/test/web/activity_pub/mrf/hellthread_policy_test.exs b/test/web/activity_pub/mrf/hellthread_policy_test.exs
index 6e9daa7f9..26f5bcdaa 100644
--- a/test/web/activity_pub/mrf/hellthread_policy_test.exs
+++ b/test/web/activity_pub/mrf/hellthread_policy_test.exs
@@ -50,7 +50,8 @@ test "rejects the message if the recipient count is above reject_threshold", %{
} do
Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2})
- {:reject, nil} = filter(message)
+ assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} ==
+ filter(message)
end
test "does not reject the message if the recipient count is below reject_threshold", %{
diff --git a/test/web/activity_pub/mrf/keyword_policy_test.exs b/test/web/activity_pub/mrf/keyword_policy_test.exs
index fd1f7aec8..b3d0f3d90 100644
--- a/test/web/activity_pub/mrf/keyword_policy_test.exs
+++ b/test/web/activity_pub/mrf/keyword_policy_test.exs
@@ -25,7 +25,8 @@ test "rejects if string matches in content" do
}
}
- assert {:reject, nil} == KeywordPolicy.filter(message)
+ assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} =
+ KeywordPolicy.filter(message)
end
test "rejects if string matches in summary" do
@@ -39,7 +40,8 @@ test "rejects if string matches in summary" do
}
}
- assert {:reject, nil} == KeywordPolicy.filter(message)
+ assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} =
+ KeywordPolicy.filter(message)
end
test "rejects if regex matches in content" do
@@ -55,7 +57,8 @@ test "rejects if regex matches in content" do
}
}
- {:reject, nil} == KeywordPolicy.filter(message)
+ {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
+ KeywordPolicy.filter(message)
end)
end
@@ -72,7 +75,8 @@ test "rejects if regex matches in summary" do
}
}
- {:reject, nil} == KeywordPolicy.filter(message)
+ {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
+ KeywordPolicy.filter(message)
end)
end
end
diff --git a/test/web/activity_pub/mrf/mention_policy_test.exs b/test/web/activity_pub/mrf/mention_policy_test.exs
index aa003bef5..220309cc9 100644
--- a/test/web/activity_pub/mrf/mention_policy_test.exs
+++ b/test/web/activity_pub/mrf/mention_policy_test.exs
@@ -76,7 +76,8 @@ test "to" do
"to" => ["https://example.com/blocked"]
}
- assert MentionPolicy.filter(message) == {:reject, nil}
+ assert MentionPolicy.filter(message) ==
+ {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
end
test "cc" do
@@ -88,7 +89,8 @@ test "cc" do
"cc" => ["https://example.com/blocked"]
}
- assert MentionPolicy.filter(message) == {:reject, nil}
+ assert MentionPolicy.filter(message) ==
+ {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
end
end
end
diff --git a/test/web/activity_pub/mrf/reject_non_public_test.exs b/test/web/activity_pub/mrf/reject_non_public_test.exs
index f36299b86..58b46b9a2 100644
--- a/test/web/activity_pub/mrf/reject_non_public_test.exs
+++ b/test/web/activity_pub/mrf/reject_non_public_test.exs
@@ -64,7 +64,7 @@ test "it's rejected when addrer of message in the follower addresses of user and
}
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false)
- assert {:reject, nil} = RejectNonPublic.filter(message)
+ assert {:reject, _} = RejectNonPublic.filter(message)
end
end
@@ -94,7 +94,7 @@ test "it's reject when direct messages aren't allow" do
}
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false)
- assert {:reject, nil} = RejectNonPublic.filter(message)
+ assert {:reject, _} = RejectNonPublic.filter(message)
end
end
end
diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/web/activity_pub/mrf/simple_policy_test.exs
index b7b9bc6a2..e842d8d8d 100644
--- a/test/web/activity_pub/mrf/simple_policy_test.exs
+++ b/test/web/activity_pub/mrf/simple_policy_test.exs
@@ -124,7 +124,7 @@ test "has a matching host" do
report_message = build_report_message()
local_message = build_local_message()
- assert SimplePolicy.filter(report_message) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(report_message)
assert SimplePolicy.filter(local_message) == {:ok, local_message}
end
@@ -133,7 +133,7 @@ test "match with wildcard domain" do
report_message = build_report_message()
local_message = build_local_message()
- assert SimplePolicy.filter(report_message) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(report_message)
assert SimplePolicy.filter(local_message) == {:ok, local_message}
end
end
@@ -241,7 +241,7 @@ test "activity has a matching host" do
remote_message = build_remote_message()
- assert SimplePolicy.filter(remote_message) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(remote_message)
end
test "activity matches with wildcard domain" do
@@ -249,7 +249,7 @@ test "activity matches with wildcard domain" do
remote_message = build_remote_message()
- assert SimplePolicy.filter(remote_message) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(remote_message)
end
test "actor has a matching host" do
@@ -257,7 +257,7 @@ test "actor has a matching host" do
remote_user = build_remote_user()
- assert SimplePolicy.filter(remote_user) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(remote_user)
end
end
@@ -279,7 +279,7 @@ test "is not empty but activity doesn't have a matching host" do
remote_message = build_remote_message()
assert SimplePolicy.filter(local_message) == {:ok, local_message}
- assert SimplePolicy.filter(remote_message) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(remote_message)
end
test "activity has a matching host" do
@@ -429,7 +429,7 @@ test "it accepts deletions even from non-whitelisted servers" do
test "it rejects the deletion" do
deletion_message = build_remote_deletion_message()
- assert SimplePolicy.filter(deletion_message) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(deletion_message)
end
end
@@ -439,7 +439,7 @@ test "it rejects the deletion" do
test "it rejects the deletion" do
deletion_message = build_remote_deletion_message()
- assert SimplePolicy.filter(deletion_message) == {:reject, nil}
+ assert {:reject, _} = SimplePolicy.filter(deletion_message)
end
end
diff --git a/test/web/activity_pub/mrf/tag_policy_test.exs b/test/web/activity_pub/mrf/tag_policy_test.exs
index e7793641a..6ff71d640 100644
--- a/test/web/activity_pub/mrf/tag_policy_test.exs
+++ b/test/web/activity_pub/mrf/tag_policy_test.exs
@@ -12,8 +12,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do
describe "mrf_tag:disable-any-subscription" do
test "rejects message" do
actor = insert(:user, tags: ["mrf_tag:disable-any-subscription"])
- message = %{"object" => actor.ap_id, "type" => "Follow"}
- assert {:reject, nil} = TagPolicy.filter(message)
+ message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => actor.ap_id}
+ assert {:reject, _} = TagPolicy.filter(message)
end
end
@@ -22,7 +22,7 @@ test "rejects non-local follow requests" do
actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: false)
message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
- assert {:reject, nil} = TagPolicy.filter(message)
+ assert {:reject, _} = TagPolicy.filter(message)
end
test "allows non-local follow requests" do
diff --git a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs
index ba1b69658..8e1ad5bc8 100644
--- a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs
+++ b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs
@@ -26,6 +26,6 @@ test "rejected if allow list isn't empty and user not in allow list" do
actor = insert(:user)
Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]})
message = %{"actor" => actor.ap_id}
- assert UserAllowListPolicy.filter(message) == {:reject, nil}
+ assert {:reject, _} = UserAllowListPolicy.filter(message)
end
end
diff --git a/test/web/activity_pub/mrf/vocabulary_policy_test.exs b/test/web/activity_pub/mrf/vocabulary_policy_test.exs
index 69f22bb77..2bceb67ee 100644
--- a/test/web/activity_pub/mrf/vocabulary_policy_test.exs
+++ b/test/web/activity_pub/mrf/vocabulary_policy_test.exs
@@ -46,7 +46,7 @@ test "it does not accept disallowed child objects" do
}
}
- {:reject, nil} = VocabularyPolicy.filter(message)
+ {:reject, _} = VocabularyPolicy.filter(message)
end
test "it does not accept disallowed parent types" do
@@ -60,7 +60,7 @@ test "it does not accept disallowed parent types" do
}
}
- {:reject, nil} = VocabularyPolicy.filter(message)
+ {:reject, _} = VocabularyPolicy.filter(message)
end
end
@@ -75,7 +75,7 @@ test "it rejects based on parent activity type" do
"object" => "whatever"
}
- {:reject, nil} = VocabularyPolicy.filter(message)
+ {:reject, _} = VocabularyPolicy.filter(message)
end
test "it rejects based on child object type" do
@@ -89,7 +89,7 @@ test "it rejects based on child object type" do
}
}
- {:reject, nil} = VocabularyPolicy.filter(message)
+ {:reject, _} = VocabularyPolicy.filter(message)
end
test "it passes through objects that aren't disallowed" do
diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs
index 8deb64501..f2a231eaf 100644
--- a/test/web/activity_pub/pipeline_test.exs
+++ b/test/web/activity_pub/pipeline_test.exs
@@ -14,6 +14,51 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do
:ok
end
+ test "when given an `object_data` in meta, Federation will receive a the original activity with the `object` field set to this embedded object" do
+ activity = insert(:note_activity)
+ object = %{"id" => "1", "type" => "Love"}
+ meta = [local: true, object_data: object]
+
+ activity_with_object = %{activity | data: Map.put(activity.data, "object", object)}
+
+ with_mocks([
+ {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
+ {
+ Pleroma.Web.ActivityPub.MRF,
+ [],
+ [filter: fn o -> {:ok, o} end]
+ },
+ {
+ Pleroma.Web.ActivityPub.ActivityPub,
+ [],
+ [persist: fn o, m -> {:ok, o, m} end]
+ },
+ {
+ Pleroma.Web.ActivityPub.SideEffects,
+ [],
+ [
+ handle: fn o, m -> {:ok, o, m} end,
+ handle_after_transaction: fn m -> m end
+ ]
+ },
+ {
+ Pleroma.Web.Federator,
+ [],
+ [publish: fn _o -> :ok end]
+ }
+ ]) do
+ assert {:ok, ^activity, ^meta} =
+ Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
+
+ assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
+ assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
+ assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
+ assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
+ refute called(Pleroma.Web.Federator.publish(activity))
+ assert_called(Pleroma.Web.Federator.publish(activity_with_object))
+ end
+ end
+
test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
activity = insert(:note_activity)
meta = [local: true]
diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs
index c2bc38d52..b9388b966 100644
--- a/test/web/activity_pub/publisher_test.exs
+++ b/test/web/activity_pub/publisher_test.exs
@@ -123,6 +123,39 @@ test "it returns inbox for messages involving single recipients in total" do
end
describe "publish_one/1" do
+ test "publish to url with with different ports" do
+ inbox80 = "http://42.site/users/nick1/inbox"
+ inbox42 = "http://42.site:42/users/nick1/inbox"
+
+ mock(fn
+ %{method: :post, url: "http://42.site:42/users/nick1/inbox"} ->
+ {:ok, %Tesla.Env{status: 200, body: "port 42"}}
+
+ %{method: :post, url: "http://42.site/users/nick1/inbox"} ->
+ {:ok, %Tesla.Env{status: 200, body: "port 80"}}
+ end)
+
+ actor = insert(:user)
+
+ assert {:ok, %{body: "port 42"}} =
+ Publisher.publish_one(%{
+ inbox: inbox42,
+ json: "{}",
+ actor: actor,
+ id: 1,
+ unreachable_since: true
+ })
+
+ assert {:ok, %{body: "port 80"}} =
+ Publisher.publish_one(%{
+ inbox: inbox80,
+ json: "{}",
+ actor: actor,
+ id: 1,
+ unreachable_since: true
+ })
+ end
+
test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
Instances,
[:passthrough],
@@ -131,7 +164,6 @@ test "it returns inbox for messages involving single recipients in total" do
inbox = "http://200.site/users/nick1/inbox"
assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
-
assert called(Instances.set_reachable(inbox))
end
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
index 2649b060a..4a08eb7ee 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -312,8 +312,12 @@ test "when activation is required", %{delete: delete, user: user} do
}
end
- test "deletes the original block", %{block_undo: block_undo, block: block} do
- {:ok, _block_undo, _} = SideEffects.handle(block_undo)
+ test "deletes the original block", %{
+ block_undo: block_undo,
+ block: block
+ } do
+ {:ok, _block_undo, _meta} = SideEffects.handle(block_undo)
+
refute Activity.get_by_id(block.id)
end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 7269e81bb..92ab0f28f 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -160,7 +160,7 @@ test "it does not crash if the object in inReplyTo can't be fetched" do
assert capture_log(fn ->
{:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
- end) =~ "[error] Couldn't fetch \"https://404.site/whatever\", error: nil"
+ end) =~ "[warn] Couldn't fetch \"https://404.site/whatever\", error: nil"
end
test "it works for incoming notices" do
@@ -663,7 +663,7 @@ test "it accepts Flag activities" do
"id" => activity.data["id"],
"content" => "test post",
"published" => object.data["published"],
- "actor" => AccountView.render("show.json", %{user: user})
+ "actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true})
}
message = %{
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
index 361dc5a41..d50213545 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/web/activity_pub/utils_test.exs
@@ -482,7 +482,8 @@ test "returns map with Flag object" do
"id" => activity_ap_id,
"content" => content,
"published" => activity.object.data["published"],
- "actor" => AccountView.render("show.json", %{user: target_account})
+ "actor" =>
+ AccountView.render("show.json", %{user: target_account, skip_visibility_check: true})
}
assert %{
diff --git a/test/web/admin_api/controllers/admin_api_controller_test.exs b/test/web/admin_api/controllers/admin_api_controller_test.exs
index da91cd552..b5d5bd8c7 100644
--- a/test/web/admin_api/controllers/admin_api_controller_test.exs
+++ b/test/web/admin_api/controllers/admin_api_controller_test.exs
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
import ExUnit.CaptureLog
import Mock
import Pleroma.Factory
+ import Swoosh.TestAssertions
alias Pleroma.Activity
alias Pleroma.Config
@@ -348,7 +349,9 @@ test "Show", %{conn: conn} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
assert expected == json_response(conn, 200)
@@ -612,6 +615,8 @@ test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
describe "GET /api/pleroma/admin/users" do
test "renders users array for the first page", %{conn: conn, admin: admin} do
user = insert(:user, local: false, tags: ["foo", "bar"])
+ user2 = insert(:user, approval_pending: true, registration_reason: "I'm a chill dude")
+
conn = get(conn, "/api/pleroma/admin/users?page=1")
users =
@@ -626,7 +631,9 @@ test "renders users array for the first page", %{conn: conn, admin: admin} do
"avatar" => User.avatar_url(admin) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(admin.name || admin.nickname),
"confirmation_pending" => false,
- "url" => admin.ap_id
+ "approval_pending" => false,
+ "url" => admin.ap_id,
+ "registration_reason" => nil
},
%{
"deactivated" => user.deactivated,
@@ -638,13 +645,29 @@ test "renders users array for the first page", %{conn: conn, admin: admin} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
+ },
+ %{
+ "deactivated" => user2.deactivated,
+ "id" => user2.id,
+ "nickname" => user2.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => true,
+ "tags" => [],
+ "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user2.name || user2.nickname),
+ "confirmation_pending" => false,
+ "approval_pending" => true,
+ "url" => user2.ap_id,
+ "registration_reason" => "I'm a chill dude"
}
]
|> Enum.sort_by(& &1["nickname"])
assert json_response(conn, 200) == %{
- "count" => 2,
+ "count" => 3,
"page_size" => 50,
"users" => users
}
@@ -711,7 +734,9 @@ test "regular search", %{conn: conn} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -737,7 +762,9 @@ test "search by domain", %{conn: conn} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -763,7 +790,9 @@ test "search by full nickname", %{conn: conn} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -789,7 +818,9 @@ test "search by display name", %{conn: conn} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -815,7 +846,9 @@ test "search by email", %{conn: conn} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -841,7 +874,9 @@ test "regular search with page size", %{conn: conn} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -862,7 +897,9 @@ test "regular search with page size", %{conn: conn} do
"avatar" => User.avatar_url(user2) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user2.name || user2.nickname),
"confirmation_pending" => false,
- "url" => user2.ap_id
+ "approval_pending" => false,
+ "url" => user2.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -895,7 +932,9 @@ test "only local users" do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -921,7 +960,9 @@ test "only local users with no query", %{conn: conn, admin: old_admin} do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
},
%{
"deactivated" => admin.deactivated,
@@ -933,7 +974,9 @@ test "only local users with no query", %{conn: conn, admin: old_admin} do
"avatar" => User.avatar_url(admin) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(admin.name || admin.nickname),
"confirmation_pending" => false,
- "url" => admin.ap_id
+ "approval_pending" => false,
+ "url" => admin.ap_id,
+ "registration_reason" => nil
},
%{
"deactivated" => false,
@@ -945,7 +988,9 @@ test "only local users with no query", %{conn: conn, admin: old_admin} do
"avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
"confirmation_pending" => false,
- "url" => old_admin.ap_id
+ "approval_pending" => false,
+ "url" => old_admin.ap_id,
+ "registration_reason" => nil
}
]
|> Enum.sort_by(& &1["nickname"])
@@ -957,6 +1002,44 @@ test "only local users with no query", %{conn: conn, admin: old_admin} do
}
end
+ test "only unapproved users", %{conn: conn} do
+ user =
+ insert(:user,
+ nickname: "sadboy",
+ approval_pending: true,
+ registration_reason: "Plz let me in!"
+ )
+
+ insert(:user, nickname: "happyboy", approval_pending: false)
+
+ conn = get(conn, "/api/pleroma/admin/users?filters=need_approval")
+
+ users =
+ [
+ %{
+ "deactivated" => user.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => true,
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname),
+ "confirmation_pending" => false,
+ "approval_pending" => true,
+ "url" => user.ap_id,
+ "registration_reason" => "Plz let me in!"
+ }
+ ]
+ |> Enum.sort_by(& &1["nickname"])
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => users
+ }
+ end
+
test "load only admins", %{conn: conn, admin: admin} do
second_admin = insert(:user, is_admin: true)
insert(:user)
@@ -976,7 +1059,9 @@ test "load only admins", %{conn: conn, admin: admin} do
"avatar" => User.avatar_url(admin) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(admin.name || admin.nickname),
"confirmation_pending" => false,
- "url" => admin.ap_id
+ "approval_pending" => false,
+ "url" => admin.ap_id,
+ "registration_reason" => nil
},
%{
"deactivated" => false,
@@ -988,7 +1073,9 @@ test "load only admins", %{conn: conn, admin: admin} do
"avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
"confirmation_pending" => false,
- "url" => second_admin.ap_id
+ "approval_pending" => false,
+ "url" => second_admin.ap_id,
+ "registration_reason" => nil
}
]
|> Enum.sort_by(& &1["nickname"])
@@ -1021,7 +1108,9 @@ test "load only moderators", %{conn: conn} do
"avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
"confirmation_pending" => false,
- "url" => moderator.ap_id
+ "approval_pending" => false,
+ "url" => moderator.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -1047,7 +1136,9 @@ test "load users with tags list", %{conn: conn} do
"avatar" => User.avatar_url(user1) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user1.name || user1.nickname),
"confirmation_pending" => false,
- "url" => user1.ap_id
+ "approval_pending" => false,
+ "url" => user1.ap_id,
+ "registration_reason" => nil
},
%{
"deactivated" => false,
@@ -1059,7 +1150,9 @@ test "load users with tags list", %{conn: conn} do
"avatar" => User.avatar_url(user2) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user2.name || user2.nickname),
"confirmation_pending" => false,
- "url" => user2.ap_id
+ "approval_pending" => false,
+ "url" => user2.ap_id,
+ "registration_reason" => nil
}
]
|> Enum.sort_by(& &1["nickname"])
@@ -1099,7 +1192,9 @@ test "it works with multiple filters" do
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -1124,7 +1219,9 @@ test "it omits relay user", %{admin: admin, conn: conn} do
"avatar" => User.avatar_url(admin) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(admin.name || admin.nickname),
"confirmation_pending" => false,
- "url" => admin.ap_id
+ "approval_pending" => false,
+ "url" => admin.ap_id,
+ "registration_reason" => nil
}
]
}
@@ -1171,6 +1268,26 @@ test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
"@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
end
+ test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do
+ user_one = insert(:user, approval_pending: true)
+ user_two = insert(:user, approval_pending: true)
+
+ conn =
+ patch(
+ conn,
+ "/api/pleroma/admin/users/approve",
+ %{nicknames: [user_one.nickname, user_two.nickname]}
+ )
+
+ response = json_response(conn, 200)
+ assert Enum.map(response["users"], & &1["approval_pending"]) == [false, false]
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
+ end
+
test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
user = insert(:user)
@@ -1187,7 +1304,9 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admi
"avatar" => User.avatar_url(user) |> MediaProxy.url(),
"display_name" => HTML.strip_tags(user.name || user.nickname),
"confirmation_pending" => false,
- "url" => user.ap_id
+ "approval_pending" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil
}
log_entry = Repo.one(ModerationLog)
@@ -1731,6 +1850,9 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do
"@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
second_user.nickname
}"
+
+ ObanHelpers.perform_all()
+ assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user))
end
end
diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs
index e0e3d4153..b974cedd5 100644
--- a/test/web/admin_api/search_test.exs
+++ b/test/web/admin_api/search_test.exs
@@ -166,5 +166,16 @@ test "it returns user by email" do
assert total == 3
assert count == 1
end
+
+ test "it returns unapproved user" do
+ unapproved = insert(:user, approval_pending: true)
+ insert(:user)
+ insert(:user)
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^unapproved], count} = Search.user(%{need_approval: true})
+ assert total == 3
+ assert count == 1
+ end
end
end
diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs
index f00b0afb2..5a02292be 100644
--- a/test/web/admin_api/views/report_view_test.exs
+++ b/test/web/admin_api/views/report_view_test.exs
@@ -4,11 +4,14 @@
defmodule Pleroma.Web.AdminAPI.ReportViewTest do
use Pleroma.DataCase
+
import Pleroma.Factory
+
+ alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.Report
alias Pleroma.Web.AdminAPI.ReportView
alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.MastodonAPI
alias Pleroma.Web.MastodonAPI.StatusView
test "renders a report" do
@@ -21,13 +24,16 @@ test "renders a report" do
content: nil,
actor:
Map.merge(
- AccountView.render("show.json", %{user: user}),
- Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})
+ MastodonAPI.AccountView.render("show.json", %{user: user, skip_visibility_check: true}),
+ AdminAPI.AccountView.render("show.json", %{user: user})
),
account:
Map.merge(
- AccountView.render("show.json", %{user: other_user}),
- Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})
+ MastodonAPI.AccountView.render("show.json", %{
+ user: other_user,
+ skip_visibility_check: true
+ }),
+ AdminAPI.AccountView.render("show.json", %{user: other_user})
),
statuses: [],
notes: [],
@@ -56,13 +62,16 @@ test "includes reported statuses" do
content: nil,
actor:
Map.merge(
- AccountView.render("show.json", %{user: user}),
- Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})
+ MastodonAPI.AccountView.render("show.json", %{user: user, skip_visibility_check: true}),
+ AdminAPI.AccountView.render("show.json", %{user: user})
),
account:
Map.merge(
- AccountView.render("show.json", %{user: other_user}),
- Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})
+ MastodonAPI.AccountView.render("show.json", %{
+ user: other_user,
+ skip_visibility_check: true
+ }),
+ AdminAPI.AccountView.render("show.json", %{user: other_user})
),
statuses: [StatusView.render("show.json", %{activity: activity})],
state: "open",
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 7e11fede3..313dda21b 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -624,14 +624,27 @@ test "unreacting to a status with an emoji" do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
- {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
+ clear_config([:instance, :federating], true)
- {:ok, unreaction} = CommonAPI.unreact_with_emoji(activity.id, user, "👍")
+ with_mock Pleroma.Web.Federator,
+ publish: fn _ -> nil end do
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
+ {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
- assert unreaction.data["type"] == "Undo"
- assert unreaction.data["object"] == reaction.data["id"]
- assert unreaction.local
+ {:ok, unreaction} = CommonAPI.unreact_with_emoji(activity.id, user, "👍")
+
+ assert unreaction.data["type"] == "Undo"
+ assert unreaction.data["object"] == reaction.data["id"]
+ assert unreaction.local
+
+ # On federation, it contains the undone (and deleted) object
+ unreaction_with_object = %{
+ unreaction
+ | data: Map.put(unreaction.data, "object", reaction.data)
+ }
+
+ assert called(Pleroma.Web.Federator.publish(unreaction_with_object))
+ end
end
test "repeating a status" do
diff --git a/test/web/feed/user_controller_test.exs b/test/web/feed/user_controller_test.exs
index fa2ed1ea5..0d2a61967 100644
--- a/test/web/feed/user_controller_test.exs
+++ b/test/web/feed/user_controller_test.exs
@@ -181,6 +181,17 @@ test "returns feed with public and unlisted activities", %{conn: conn} do
assert activity_titles == ['public', 'unlisted']
end
+
+ test "returns 404 when the user is remote", %{conn: conn} do
+ user = insert(:user, local: false)
+
+ {:ok, _} = CommonAPI.post(user, %{status: "test"})
+
+ assert conn
+ |> put_req_header("accept", "application/atom+xml")
+ |> get(user_feed_path(conn, :feed, user.nickname))
+ |> response(404)
+ end
end
# Note: see ActivityPubControllerTest for JSON format tests
diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs
index 9c7b5e9b2..e6b283aab 100644
--- a/test/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/web/mastodon_api/controllers/account_controller_test.exs
@@ -583,6 +583,15 @@ test "getting followers, pagination", %{user: user, conn: conn} do
|> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}")
|> json_response_and_validate_schema(200)
+ assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
+ conn
+ |> get(
+ "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{
+ follower3_id
+ }"
+ )
+ |> json_response_and_validate_schema(200)
+
res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}")
assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200)
@@ -654,6 +663,16 @@ test "getting following, pagination", %{user: user, conn: conn} do
assert id2 == following2.id
assert id1 == following1.id
+ res_conn =
+ get(
+ conn,
+ "/api/v1/accounts/#{user.id}/following?id=#{user.id}&limit=20&max_id=#{following3.id}"
+ )
+
+ assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
+ assert id2 == following2.id
+ assert id1 == following1.id
+
res_conn =
get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
@@ -885,6 +904,7 @@ test "blocking / unblocking a user" do
end
setup do: clear_config([:instance, :account_activation_required])
+ setup do: clear_config([:instance, :account_approval_required])
test "Account registration via Application", %{conn: conn} do
conn =
@@ -949,6 +969,75 @@ test "Account registration via Application", %{conn: conn} do
assert token_from_db.user.confirmation_pending
end
+ test "Account registration via app with account_approval_required", %{conn: conn} do
+ Pleroma.Config.put([:instance, :account_approval_required], true)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/apps", %{
+ client_name: "client_name",
+ redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
+ scopes: "read, write, follow"
+ })
+
+ assert %{
+ "client_id" => client_id,
+ "client_secret" => client_secret,
+ "id" => _,
+ "name" => "client_name",
+ "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
+ "vapid_key" => _,
+ "website" => nil
+ } = json_response_and_validate_schema(conn, 200)
+
+ conn =
+ post(conn, "/oauth/token", %{
+ grant_type: "client_credentials",
+ client_id: client_id,
+ client_secret: client_secret
+ })
+
+ assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
+ json_response(conn, 200)
+
+ assert token
+ token_from_db = Repo.get_by(Token, token: token)
+ assert token_from_db
+ assert refresh
+ assert scope == "read write follow"
+
+ conn =
+ build_conn()
+ |> put_req_header("content-type", "multipart/form-data")
+ |> put_req_header("authorization", "Bearer " <> token)
+ |> post("/api/v1/accounts", %{
+ username: "lain",
+ email: "lain@example.org",
+ password: "PlzDontHackLain",
+ bio: "Test Bio",
+ agreement: true,
+ reason: "I'm a cool dude, bro"
+ })
+
+ %{
+ "access_token" => token,
+ "created_at" => _created_at,
+ "scope" => ^scope,
+ "token_type" => "Bearer"
+ } = json_response_and_validate_schema(conn, 200)
+
+ token_from_db = Repo.get_by(Token, token: token)
+ assert token_from_db
+ token_from_db = Repo.preload(token_from_db, :user)
+ assert token_from_db.user
+
+ assert token_from_db.user.confirmation_pending
+ assert token_from_db.user.approval_pending
+
+ assert token_from_db.user.registration_reason == "I'm a cool dude, bro"
+ end
+
test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
_user = insert(:user, email: "lain@example.org")
app_token = insert(:oauth_token, user: nil)
diff --git a/test/web/mastodon_api/controllers/domain_block_controller_test.exs b/test/web/mastodon_api/controllers/domain_block_controller_test.exs
index 01a24afcf..664654500 100644
--- a/test/web/mastodon_api/controllers/domain_block_controller_test.exs
+++ b/test/web/mastodon_api/controllers/domain_block_controller_test.exs
@@ -32,6 +32,38 @@ test "blocking / unblocking a domain" do
refute User.blocks?(user, other_user)
end
+ test "blocking a domain via query params" do
+ %{user: user, conn: conn} = oauth_access(["write:blocks"])
+ other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
+
+ ret_conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/domain_blocks?domain=dogwhistle.zone")
+
+ assert %{} == json_response_and_validate_schema(ret_conn, 200)
+ user = User.get_cached_by_ap_id(user.ap_id)
+ assert User.blocks?(user, other_user)
+ end
+
+ test "unblocking a domain via query params" do
+ %{user: user, conn: conn} = oauth_access(["write:blocks"])
+ other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
+
+ User.block_domain(user, "dogwhistle.zone")
+ user = refresh_record(user)
+ assert User.blocks?(user, other_user)
+
+ ret_conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> delete("/api/v1/domain_blocks?domain=dogwhistle.zone")
+
+ assert %{} == json_response_and_validate_schema(ret_conn, 200)
+ user = User.get_cached_by_ap_id(user.ap_id)
+ refute User.blocks?(user, other_user)
+ end
+
test "getting a list of domain blocks" do
%{user: user, conn: conn} = oauth_access(["read:blocks"])
diff --git a/test/web/mastodon_api/controllers/instance_controller_test.exs b/test/web/mastodon_api/controllers/instance_controller_test.exs
index cc880d82c..6a9ccd979 100644
--- a/test/web/mastodon_api/controllers/instance_controller_test.exs
+++ b/test/web/mastodon_api/controllers/instance_controller_test.exs
@@ -27,6 +27,7 @@ test "get instance information", %{conn: conn} do
"thumbnail" => _,
"languages" => _,
"registrations" => _,
+ "approval_required" => _,
"poll_limits" => _,
"upload_limit" => _,
"avatar_upload_limit" => _,
diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs
index fd2de8d80..d34f300da 100644
--- a/test/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/web/mastodon_api/controllers/status_controller_test.exs
@@ -22,6 +22,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
setup do: clear_config([:instance, :federating])
setup do: clear_config([:instance, :allow_relay])
setup do: clear_config([:rich_media, :enabled])
+ setup do: clear_config([:mrf, :policies])
+ setup do: clear_config([:mrf_keyword, :reject])
describe "posting statuses" do
setup do: oauth_access(["write:statuses"])
@@ -157,6 +159,17 @@ test "it fails to create a status if `expires_in` is less or equal than an hour"
|> json_response_and_validate_schema(422)
end
+ test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do
+ Pleroma.Config.put([:mrf_keyword, :reject], ["GNO"])
+ Pleroma.Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+
+ assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("api/v1/statuses", %{"status" => "GNO/Linux"})
+ |> json_response_and_validate_schema(422)
+ end
+
test "posting an undefined status with an attachment", %{user: user, conn: conn} do
file = %Plug.Upload{
content_type: "image/jpg",
diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs
index 17f035add..8f37efa3c 100644
--- a/test/web/mastodon_api/views/account_view_test.exs
+++ b/test/web/mastodon_api/views/account_view_test.exs
@@ -95,7 +95,7 @@ test "Represent a user account" do
}
}
- assert expected == AccountView.render("show.json", %{user: user})
+ assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
test "Favicon is nil when :instances_favicons is disabled" do
@@ -108,22 +108,20 @@ test "Favicon is nil when :instances_favicons is disabled" do
favicon:
"https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png"
}
- } = AccountView.render("show.json", %{user: user})
+ } = AccountView.render("show.json", %{user: user, skip_visibility_check: true})
Config.put([:instances_favicons, :enabled], false)
- assert %{pleroma: %{favicon: nil}} = AccountView.render("show.json", %{user: user})
+ assert %{pleroma: %{favicon: nil}} =
+ AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
test "Represent the user account for the account owner" do
user = insert(:user)
notification_settings = %{
- followers: true,
- follows: true,
- non_followers: true,
- non_follows: true,
- privacy_option: false
+ block_from_strangers: false,
+ hide_notification_contents: false
}
privacy = user.default_scope
@@ -192,7 +190,7 @@ test "Represent a Service(bot) account" do
}
}
- assert expected == AccountView.render("show.json", %{user: user})
+ assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
test "Represent a Funkwhale channel" do
@@ -201,7 +199,9 @@ test "Represent a Funkwhale channel" do
"https://channels.tests.funkwhale.audio/federation/actors/compositions"
)
- assert represented = AccountView.render("show.json", %{user: user})
+ assert represented =
+ AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+
assert represented.acct == "compositions@channels.tests.funkwhale.audio"
assert represented.url == "https://channels.tests.funkwhale.audio/channels/compositions"
end
@@ -226,6 +226,23 @@ test "Represent a smaller mention" do
assert expected == AccountView.render("mention.json", %{user: user})
end
+ test "demands :for or :skip_visibility_check option for account rendering" do
+ clear_config([:restrict_unauthenticated, :profiles, :local], false)
+
+ user = insert(:user)
+ user_id = user.id
+
+ assert %{id: ^user_id} = AccountView.render("show.json", %{user: user, for: nil})
+ assert %{id: ^user_id} = AccountView.render("show.json", %{user: user, for: user})
+
+ assert %{id: ^user_id} =
+ AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+
+ assert_raise RuntimeError, ~r/:skip_visibility_check or :for option is required/, fn ->
+ AccountView.render("show.json", %{user: user})
+ end
+ end
+
describe "relationship" do
defp test_relationship_rendering(user, other_user, expected_result) do
opts = %{user: user, target: other_user, relationships: nil}
@@ -339,7 +356,7 @@ test "returns the settings store if the requesting user is the represented user
assert result.pleroma.settings_store == %{:fe => "test"}
- result = AccountView.render("show.json", %{user: user, with_pleroma_settings: true})
+ result = AccountView.render("show.json", %{user: user, for: nil, with_pleroma_settings: true})
assert result.pleroma[:settings_store] == nil
result = AccountView.render("show.json", %{user: user, for: user})
@@ -348,13 +365,13 @@ test "returns the settings store if the requesting user is the represented user
test "doesn't sanitize display names" do
user = insert(:user, name: "
")
- result = AccountView.render("show.json", %{user: user})
+ result = AccountView.render("show.json", %{user: user, skip_visibility_check: true})
assert result.display_name == "
"
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})
+ result = AccountView.render("show.json", %{user: user, skip_visibility_check: true})
assert result.following_count == 0
assert result.followers_count == 0
@@ -378,7 +395,7 @@ test "shows when follows/followers stats are hidden and sets follow/follower cou
followers_count: 0,
following_count: 0,
pleroma: %{hide_follows_count: true, hide_followers_count: true}
- } = AccountView.render("show.json", %{user: user})
+ } = AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
test "shows when follows/followers are hidden" do
@@ -391,7 +408,7 @@ test "shows when follows/followers are hidden" do
followers_count: 1,
following_count: 1,
pleroma: %{hide_follows: true, hide_followers: true}
- } = AccountView.render("show.json", %{user: user})
+ } = AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
test "shows actual follower/following count to the account owner" do
@@ -534,7 +551,7 @@ test "uses mediaproxy urls when it's enabled" do
emoji: %{"joker_smile" => "https://evil.website/society.png"}
)
- AccountView.render("show.json", %{user: user})
+ AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|> Enum.all?(fn
{key, url} when key in [:avatar, :avatar_static, :header, :header_static] ->
String.starts_with?(url, Pleroma.Web.base_url())
diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs
index fa26b3129..8703d5ba7 100644
--- a/test/web/mastodon_api/views/status_view_test.exs
+++ b/test/web/mastodon_api/views/status_view_test.exs
@@ -56,6 +56,23 @@ test "has an emoji reaction list" do
]
end
+ test "works correctly with badly formatted emojis" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "yo"})
+
+ activity
+ |> Object.normalize(false)
+ |> Object.update_data(%{"reactions" => %{"☕" => [user.ap_id], "x" => 1}})
+
+ activity = Activity.get_by_id(activity.id)
+
+ status = StatusView.render("show.json", activity: activity, for: user)
+
+ assert status[:pleroma][:emoji_reactions] == [
+ %{name: "☕", count: 1, me: true}
+ ]
+ end
+
test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do
user = insert(:user)
@@ -177,7 +194,7 @@ test "a note activity" do
id: to_string(note.id),
uri: object_data["id"],
url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note),
- account: AccountView.render("show.json", %{user: user}),
+ account: AccountView.render("show.json", %{user: user, skip_visibility_check: true}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
card: nil,
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index d389e4ce0..1200126b8 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -19,7 +19,10 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
key: "_test",
signing_salt: "cooldude"
]
- setup do: clear_config([:instance, :account_activation_required])
+ setup do
+ clear_config([:instance, :account_activation_required])
+ clear_config([:instance, :account_approval_required])
+ end
describe "in OAuth consumer mode, " do
setup do
@@ -995,6 +998,30 @@ test "rejects token exchange for user with confirmation_pending set to true" do
}
end
+ test "rejects token exchange for valid credentials belonging to an unapproved user" do
+ password = "testpassword"
+
+ user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password), approval_pending: true)
+
+ refute Pleroma.User.account_status(user) == :active
+
+ app = insert(:oauth_app)
+
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "password",
+ "username" => user.nickname,
+ "password" => password,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert resp = json_response(conn, 403)
+ assert %{"error" => _} = resp
+ refute Map.has_key?(resp, "access_token")
+ end
+
test "rejects an invalid authorization code" do
app = insert(:oauth_app)
diff --git a/test/web/pleroma_api/controllers/chat_controller_test.exs b/test/web/pleroma_api/controllers/chat_controller_test.exs
index 82e16741d..d71e80d03 100644
--- a/test/web/pleroma_api/controllers/chat_controller_test.exs
+++ b/test/web/pleroma_api/controllers/chat_controller_test.exs
@@ -332,5 +332,27 @@ test "it return a list of chats the current user is participating in, in descend
chat_1.id |> to_string()
]
end
+
+ test "it is not affected by :restrict_unauthenticated setting (issue #1973)", %{
+ conn: conn,
+ user: user
+ } do
+ clear_config([:restrict_unauthenticated, :profiles, :local], true)
+ clear_config([:restrict_unauthenticated, :profiles, :remote], true)
+
+ user2 = insert(:user)
+ user3 = insert(:user, local: false)
+
+ {:ok, _chat_12} = Chat.get_or_create(user.id, user2.ap_id)
+ {:ok, _chat_13} = Chat.get_or_create(user.id, user3.ap_id)
+
+ result =
+ conn
+ |> get("/api/v1/pleroma/chats")
+ |> json_response_and_validate_schema(200)
+
+ account_ids = Enum.map(result, &get_in(&1, ["account", "id"]))
+ assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id])
+ end
end
end
diff --git a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs
index df58a5eb6..e113bb15f 100644
--- a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs
+++ b/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs
@@ -14,6 +14,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
)
setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
+ setup do: clear_config([:instance, :public], true)
+
setup do
admin = insert(:user, is_admin: true)
token = insert(:oauth_admin_token, user: admin)
@@ -27,6 +29,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
{:ok, %{admin_conn: admin_conn}}
end
+ test "GET /api/pleroma/emoji/packs when :public: false", %{conn: conn} do
+ Config.put([:instance, :public], false)
+ conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
+ end
+
test "GET /api/pleroma/emoji/packs", %{conn: conn} do
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
diff --git a/test/web/pleroma_api/views/chat_view_test.exs b/test/web/pleroma_api/views/chat_view_test.exs
index 14eecb1bd..02484b705 100644
--- a/test/web/pleroma_api/views/chat_view_test.exs
+++ b/test/web/pleroma_api/views/chat_view_test.exs
@@ -26,7 +26,8 @@ test "it represents a chat" do
assert represented_chat == %{
id: "#{chat.id}",
- account: AccountView.render("show.json", user: recipient),
+ account:
+ AccountView.render("show.json", user: recipient, skip_visibility_check: true),
unread: 0,
last_message: nil,
updated_at: Utils.to_masto_date(chat.updated_at)
diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs
index b48952b29..aeb5c1fbd 100644
--- a/test/web/push/impl_test.exs
+++ b/test/web/push/impl_test.exs
@@ -238,9 +238,11 @@ test "builds content for chat messages with no content" do
}
end
- test "hides details for notifications when privacy option enabled" do
+ test "hides contents of notifications when option enabled" do
user = insert(:user, nickname: "Bob")
- user2 = insert(:user, nickname: "Rob", notification_settings: %{privacy_option: true})
+
+ user2 =
+ insert(:user, nickname: "Rob", notification_settings: %{hide_notification_contents: true})
{:ok, activity} =
CommonAPI.post(user, %{
@@ -284,9 +286,11 @@ test "hides details for notifications when privacy option enabled" do
}
end
- test "returns regular content for notifications with privacy option disabled" do
+ test "returns regular content when hiding contents option disabled" do
user = insert(:user, nickname: "Bob")
- user2 = insert(:user, nickname: "Rob", notification_settings: %{privacy_option: false})
+
+ user2 =
+ insert(:user, nickname: "Rob", notification_settings: %{hide_notification_contents: false})
{:ok, activity} =
CommonAPI.post(user, %{
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index 368533292..20a45cb6f 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -4,11 +4,11 @@
defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
use Pleroma.DataCase
+ import Pleroma.Factory
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.UserInviteToken
- alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.TwitterAPI.TwitterAPI
setup_all do
@@ -27,13 +27,10 @@ test "it registers a new user and returns the user." do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = User.get_cached_by_nickname("lain")
-
- assert AccountView.render("show.json", %{user: user}) ==
- AccountView.render("show.json", %{user: fetched_user})
+ assert user == User.get_cached_by_nickname("lain")
end
- test "it registers a new user with empty string in bio and returns the user." do
+ test "it registers a new user with empty string in bio and returns the user" do
data = %{
:username => "lain",
:email => "lain@wired.jp",
@@ -45,10 +42,7 @@ test "it registers a new user with empty string in bio and returns the user." do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = User.get_cached_by_nickname("lain")
-
- assert AccountView.render("show.json", %{user: user}) ==
- AccountView.render("show.json", %{user: fetched_user})
+ assert user == User.get_cached_by_nickname("lain")
end
test "it sends confirmation email if :account_activation_required is specified in instance config" do
@@ -85,6 +79,42 @@ test "it sends confirmation email if :account_activation_required is specified i
)
end
+ test "it sends an admin email if :account_approval_required is specified in instance config" do
+ admin = insert(:user, is_admin: true)
+ setting = Pleroma.Config.get([:instance, :account_approval_required])
+
+ unless setting do
+ Pleroma.Config.put([:instance, :account_approval_required], true)
+ on_exit(fn -> Pleroma.Config.put([:instance, :account_approval_required], setting) end)
+ end
+
+ data = %{
+ :username => "lain",
+ :email => "lain@wired.jp",
+ :fullname => "lain iwakura",
+ :bio => "",
+ :password => "bear",
+ :confirm => "bear",
+ :reason => "I love anime"
+ }
+
+ {:ok, user} = TwitterAPI.register_user(data)
+ ObanHelpers.perform_all()
+
+ assert user.approval_pending
+
+ email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
+
+ notify_email = Pleroma.Config.get([:instance, :notify_email])
+ instance_name = Pleroma.Config.get([:instance, :name])
+
+ Swoosh.TestAssertions.assert_email_sent(
+ from: {instance_name, notify_email},
+ to: {admin.name, admin.email},
+ html_body: email.html_body
+ )
+ end
+
test "it registers a new user and parses mentions in the bio" do
data1 = %{
:username => "john",
@@ -134,13 +164,10 @@ test "returns user on success" do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = User.get_cached_by_nickname("vinny")
+ assert user == User.get_cached_by_nickname("vinny")
+
invite = Repo.get_by(UserInviteToken, token: invite.token)
-
assert invite.used == true
-
- assert AccountView.render("show.json", %{user: user}) ==
- AccountView.render("show.json", %{user: fetched_user})
end
test "returns error on invalid token" do
@@ -197,10 +224,8 @@ test "returns error on expired token" do
check_fn = fn invite ->
data = Map.put(data, :token, invite.token)
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = User.get_cached_by_nickname("vinny")
- assert AccountView.render("show.json", %{user: user}) ==
- AccountView.render("show.json", %{user: fetched_user})
+ assert user == User.get_cached_by_nickname("vinny")
end
{:ok, data: data, check_fn: check_fn}
@@ -260,14 +285,11 @@ test "returns user on success, after him registration fails" do
}
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = User.get_cached_by_nickname("vinny")
+ assert user == User.get_cached_by_nickname("vinny")
+
invite = Repo.get_by(UserInviteToken, token: invite.token)
-
assert invite.used == true
- assert AccountView.render("show.json", %{user: user}) ==
- AccountView.render("show.json", %{user: fetched_user})
-
data = %{
:username => "GrimReaper",
:email => "death@reapers.afterlife",
@@ -302,13 +324,10 @@ test "returns user on success" do
}
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = User.get_cached_by_nickname("vinny")
+ assert user == User.get_cached_by_nickname("vinny")
+
invite = Repo.get_by(UserInviteToken, token: invite.token)
-
refute invite.used
-
- assert AccountView.render("show.json", %{user: user}) ==
- AccountView.render("show.json", %{user: fetched_user})
end
test "error after max uses" do
@@ -327,13 +346,11 @@ test "error after max uses" do
}
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = User.get_cached_by_nickname("vinny")
+ assert user == User.get_cached_by_nickname("vinny")
+
invite = Repo.get_by(UserInviteToken, token: invite.token)
assert invite.used == true
- assert AccountView.render("show.json", %{user: user}) ==
- AccountView.render("show.json", %{user: fetched_user})
-
data = %{
:username => "GrimReaper",
:email => "death@reapers.afterlife",
diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs
index 76e9369f7..109c1e637 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/web/twitter_api/util_controller_test.exs
@@ -191,7 +191,7 @@ test "it imports blocks with different nickname variations", %{conn: conn} do
test "it updates notification settings", %{user: user, conn: conn} do
conn
|> put("/api/pleroma/notification_settings", %{
- "followers" => false,
+ "block_from_strangers" => true,
"bar" => 1
})
|> json_response(:ok)
@@ -199,27 +199,21 @@ test "it updates notification settings", %{user: user, conn: conn} do
user = refresh_record(user)
assert %Pleroma.User.NotificationSetting{
- followers: false,
- follows: true,
- non_follows: true,
- non_followers: true,
- privacy_option: false
+ block_from_strangers: true,
+ hide_notification_contents: false
} == user.notification_settings
end
- test "it updates notification privacy option", %{user: user, conn: conn} do
+ test "it updates notification settings to enable hiding contents", %{user: user, conn: conn} do
conn
- |> put("/api/pleroma/notification_settings", %{"privacy_option" => "1"})
+ |> put("/api/pleroma/notification_settings", %{"hide_notification_contents" => "1"})
|> json_response(:ok)
user = refresh_record(user)
assert %Pleroma.User.NotificationSetting{
- followers: true,
- follows: true,
- non_follows: true,
- non_followers: true,
- privacy_option: true
+ block_from_strangers: false,
+ hide_notification_contents: true
} == user.notification_settings
end
end