From 48ae3c4347f68e20db7e3e67da32be2e70599fb3 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 5 Dec 2019 20:18:25 +0700 Subject: Add support for custom modules --- lib/pleroma/application.ex | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 9dbd1e26b..5b6e233a6 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -32,6 +32,7 @@ defmodule Pleroma.Application do def start(_type, _args) do Pleroma.Config.DeprecationWarnings.warn() setup_instrumenters() + load_custom_modules() # Define workers and child supervisors to be supervised children = @@ -67,6 +68,29 @@ defmodule Pleroma.Application do Supervisor.start_link(children, opts) end + def load_custom_modules() do + dir = Pleroma.Config.get([:instance, :custom_modules_dir]) + + if dir && File.exists?(dir) do + dir + |> File.ls!() + |> Enum.map(&Path.join(dir, &1)) + |> Kernel.ParallelCompiler.compile() + |> case do + {:error, _errors, _warnings} -> + raise "Invalid custom modules" + + {:ok, modules, _warnings} -> + Enum.each(modules, fn mod -> + name = mod |> Atom.to_string() |> String.trim_leading("Elixir.") + IO.puts("Custom module loaded: #{name}") + end) + + :ok + end + end + end + defp setup_instrumenters do require Prometheus.Registry -- cgit v1.2.3 From 1216b546c6bc0540e266fe0f05829f4f683b1ce9 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 5 Dec 2019 20:29:17 +0700 Subject: Fix credo warning --- lib/pleroma/application.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 5b6e233a6..73364f141 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -68,7 +68,7 @@ defmodule Pleroma.Application do Supervisor.start_link(children, opts) end - def load_custom_modules() do + def load_custom_modules do dir = Pleroma.Config.get([:instance, :custom_modules_dir]) if dir && File.exists?(dir) do -- cgit v1.2.3 From 22fc271e23a5dd1570ea7429b563f6edc42613c4 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 6 Dec 2019 09:32:29 +0300 Subject: init tag feed --- lib/pleroma/emails/admin_email.ex | 2 +- lib/pleroma/web/feed/feed_controller.ex | 64 ----------------------- lib/pleroma/web/feed/tag_controller.ex | 36 +++++++++++++ lib/pleroma/web/feed/user_controller.ex | 66 ++++++++++++++++++++++++ lib/pleroma/web/metadata/feed.ex | 2 +- lib/pleroma/web/router.ex | 6 ++- lib/pleroma/web/templates/feed/feed/feed.xml.eex | 24 --------- lib/pleroma/web/templates/feed/feed/tag.xml.eex | 10 ++++ lib/pleroma/web/templates/feed/feed/user.xml.eex | 24 +++++++++ 9 files changed, 142 insertions(+), 92 deletions(-) delete mode 100644 lib/pleroma/web/feed/feed_controller.ex create mode 100644 lib/pleroma/web/feed/tag_controller.ex create mode 100644 lib/pleroma/web/feed/user_controller.ex delete mode 100644 lib/pleroma/web/templates/feed/feed/feed.xml.eex create mode 100644 lib/pleroma/web/templates/feed/feed/tag.xml.eex create mode 100644 lib/pleroma/web/templates/feed/feed/user.xml.eex (limited to 'lib') diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index b15e4041b..d7dd4b2e0 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Emails.AdminEmail do end defp user_url(user) do - Helpers.feed_url(Pleroma.Web.Endpoint, :feed_redirect, user.id) + Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, user.id) end def report(to, reporter, account, statuses, comment) do diff --git a/lib/pleroma/web/feed/feed_controller.ex b/lib/pleroma/web/feed/feed_controller.ex deleted file mode 100644 index d0e23007d..000000000 --- a/lib/pleroma/web/feed/feed_controller.ex +++ /dev/null @@ -1,64 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Feed.FeedController do - use Pleroma.Web, :controller - - alias Fallback.RedirectController - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.ActivityPubController - - plug(Pleroma.Plugs.SetFormatPlug when action in [:feed_redirect]) - - action_fallback(:errors) - - def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do - with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do - RedirectController.redirector_with_meta(conn, %{user: user}) - end - end - - def feed_redirect(%{assigns: %{format: format}} = conn, _params) - when format in ["json", "activity+json"] do - ActivityPubController.call(conn, :user) - end - - def feed_redirect(conn, %{"nickname" => nickname}) do - with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do - redirect(conn, external: "#{feed_url(conn, :feed, user.nickname)}.atom") - end - end - - def feed(conn, %{"nickname" => nickname} = params) do - with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do - activities = - %{ - "type" => ["Create"], - "whole_db" => true, - "actor_id" => user.ap_id - } - |> Map.merge(Map.take(params, ["max_id"])) - |> ActivityPub.fetch_public_activities() - - conn - |> put_resp_content_type("application/atom+xml") - |> render("feed.xml", - user: user, - activities: activities, - feed_config: Pleroma.Config.get([:feed]) - ) - end - end - - def errors(conn, {:error, :not_found}) do - render_error(conn, :not_found, "Not found") - end - - def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found}) - - def errors(conn, _) do - render_error(conn, :internal_server_error, "Something went wrong") - end -end diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex new file mode 100644 index 000000000..66abc186b --- /dev/null +++ b/lib/pleroma/web/feed/tag_controller.ex @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Feed.TagController do + use Pleroma.Web, :controller + + alias Pleroma.Config + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.Feed.FeedView + + def feed(conn, %{"tag" => tag} = params) do + activities = + %{ + "type" => ["Create"], + "whole_db" => true, + "tag" => parse_tag(tag) + } + |> Map.merge(Map.take(params, ["max_id"])) + |> ActivityPub.fetch_public_activities() + + conn + |> put_resp_content_type("application/atom+xml") + |> put_view(FeedView) + |> render("tag.xml", activities: activities, feed_config: Config.get([:feed])) + end + + defp parse_tag(raw_tag) when is_binary(raw_tag) do + case Enum.reverse(String.split(raw_tag, ".")) do + [format | tag] when format in ["atom", "rss"] -> Enum.join(tag, ".") + _ -> raw_tag + end + end + + defp parse_tag(raw_tag), do: raw_tag +end diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex new file mode 100644 index 000000000..e5d8427ce --- /dev/null +++ b/lib/pleroma/web/feed/user_controller.ex @@ -0,0 +1,66 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Feed.UserController do + use Pleroma.Web, :controller + + alias Fallback.RedirectController + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.ActivityPubController + alias Pleroma.Web.Feed.FeedView + + plug(Pleroma.Plugs.SetFormatPlug when action in [:feed_redirect]) + + action_fallback(:errors) + + def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do + with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do + RedirectController.redirector_with_meta(conn, %{user: user}) + end + end + + def feed_redirect(%{assigns: %{format: format}} = conn, _params) + when format in ["json", "activity+json"] do + ActivityPubController.call(conn, :user) + end + + def feed_redirect(conn, %{"nickname" => nickname}) do + with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do + redirect(conn, external: "#{user_feed_url(conn, :feed, user.nickname)}.atom") + end + end + + def feed(conn, %{"nickname" => nickname} = params) do + with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do + activities = + %{ + "type" => ["Create"], + "whole_db" => true, + "actor_id" => user.ap_id + } + |> Map.merge(Map.take(params, ["max_id"])) + |> ActivityPub.fetch_public_activities() + + conn + |> put_resp_content_type("application/atom+xml") + |> put_view(FeedView) + |> render("user.xml", + user: user, + activities: activities, + feed_config: Pleroma.Config.get([:feed]) + ) + end + end + + def errors(conn, {:error, :not_found}) do + render_error(conn, :not_found, "Not found") + end + + def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found}) + + def errors(conn, _) do + render_error(conn, :internal_server_error, "Something went wrong") + end +end diff --git a/lib/pleroma/web/metadata/feed.ex b/lib/pleroma/web/metadata/feed.ex index 8043e6c54..ee48913a7 100644 --- a/lib/pleroma/web/metadata/feed.ex +++ b/lib/pleroma/web/metadata/feed.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.Metadata.Providers.Feed do [ rel: "alternate", type: "application/atom+xml", - href: Helpers.feed_path(Endpoint, :feed, user.nickname) <> ".atom" + href: Helpers.user_feed_path(Endpoint, :feed, user.nickname) <> ".atom" ], []} ] end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e6c4f6f14..871f3bf85 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -526,8 +526,10 @@ defmodule Pleroma.Web.Router do get("/notice/:id", OStatus.OStatusController, :notice) get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player) - get("/users/:nickname/feed", Feed.FeedController, :feed) - get("/users/:nickname", Feed.FeedController, :feed_redirect) + get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed) + get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed) + + get("/tags/:tag", Feed.TagController, :feed, as: :tag_feed) get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe) end diff --git a/lib/pleroma/web/templates/feed/feed/feed.xml.eex b/lib/pleroma/web/templates/feed/feed/feed.xml.eex deleted file mode 100644 index 5ae36d345..000000000 --- a/lib/pleroma/web/templates/feed/feed/feed.xml.eex +++ /dev/null @@ -1,24 +0,0 @@ - - - - <%= feed_url(@conn, :feed, @user.nickname) <> ".atom" %> - <%= @user.nickname <> "'s timeline" %> - <%= most_recent_update(@activities, @user) %> - <%= logo(@user) %> - - - <%= render @view_module, "_author.xml", assigns %> - - <%= if last_activity(@activities) do %> - - <% end %> - - <%= for activity <- @activities do %> - <%= render @view_module, "_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> - <% end %> - diff --git a/lib/pleroma/web/templates/feed/feed/tag.xml.eex b/lib/pleroma/web/templates/feed/feed/tag.xml.eex new file mode 100644 index 000000000..52b1d7b7d --- /dev/null +++ b/lib/pleroma/web/templates/feed/feed/tag.xml.eex @@ -0,0 +1,10 @@ + + + + TAGS + diff --git a/lib/pleroma/web/templates/feed/feed/user.xml.eex b/lib/pleroma/web/templates/feed/feed/user.xml.eex new file mode 100644 index 000000000..d274c08ae --- /dev/null +++ b/lib/pleroma/web/templates/feed/feed/user.xml.eex @@ -0,0 +1,24 @@ + + + + <%= user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %> + <%= @user.nickname <> "'s timeline" %> + <%= most_recent_update(@activities, @user) %> + <%= logo(@user) %> + + + <%= render @view_module, "_author.xml", assigns %> + + <%= if last_activity(@activities) do %> + + <% end %> + + <%= for activity <- @activities do %> + <%= render @view_module, "_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> + <% end %> + -- cgit v1.2.3 From 157bceeda9124cea7ba69eaf6639ca52b3fac7c6 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 6 Dec 2019 15:04:46 +0700 Subject: Move runtime configuration from `:instance` to `:modules` --- lib/pleroma/application.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 73364f141..9d2f3f320 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -69,7 +69,7 @@ defmodule Pleroma.Application do end def load_custom_modules do - dir = Pleroma.Config.get([:instance, :custom_modules_dir]) + dir = Pleroma.Config.get([:modules, :runtime_dir]) if dir && File.exists?(dir) do dir -- cgit v1.2.3 From e4292cbfad47e59c76461fa201bab3e5f791962b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 6 Dec 2019 15:16:39 +0700 Subject: Use Kernel.inspect/2 to print loaded custom modules --- lib/pleroma/application.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 9d2f3f320..17f6b9c80 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -82,8 +82,7 @@ defmodule Pleroma.Application do {:ok, modules, _warnings} -> Enum.each(modules, fn mod -> - name = mod |> Atom.to_string() |> String.trim_leading("Elixir.") - IO.puts("Custom module loaded: #{name}") + IO.puts("Custom module loaded: #{inspect(mod)}") end) :ok -- cgit v1.2.3 From a75d4a41e03979b4d1b9af5205e457d714ff76df Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 6 Dec 2019 17:05:09 +0700 Subject: Add a test for custom runtime modules --- lib/pleroma/application.ex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 17f6b9c80..82a005700 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -81,9 +81,11 @@ defmodule Pleroma.Application do raise "Invalid custom modules" {:ok, modules, _warnings} -> - Enum.each(modules, fn mod -> - IO.puts("Custom module loaded: #{inspect(mod)}") - end) + if @env != :test do + Enum.each(modules, fn mod -> + IO.puts("Custom module loaded: #{inspect(mod)}") + end) + end :ok end -- cgit v1.2.3 From 84f891ea3e31c936bc990a3c2310d539df62fc44 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 9 Dec 2019 18:23:07 +0700 Subject: Add Pleroma.Utils.compile_dir/1 --- lib/pleroma/application.ex | 4 +--- lib/pleroma/utils.ex | 12 ++++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 lib/pleroma/utils.ex (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 82a005700..104620b37 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -73,9 +73,7 @@ defmodule Pleroma.Application do if dir && File.exists?(dir) do dir - |> File.ls!() - |> Enum.map(&Path.join(dir, &1)) - |> Kernel.ParallelCompiler.compile() + |> Pleroma.Utils.compile_dir() |> case do {:error, _errors, _warnings} -> raise "Invalid custom modules" diff --git a/lib/pleroma/utils.ex b/lib/pleroma/utils.ex new file mode 100644 index 000000000..8d36a0001 --- /dev/null +++ b/lib/pleroma/utils.ex @@ -0,0 +1,12 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Utils do + def compile_dir(dir) when is_binary(dir) do + dir + |> File.ls!() + |> Enum.map(&Path.join(dir, &1)) + |> Kernel.ParallelCompiler.compile() + end +end -- cgit v1.2.3 From ed92784e7cfe60756733f518efce14253b1c78d6 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 9 Dec 2019 19:11:54 +0700 Subject: Set Logger level to :info in prod --- lib/pleroma/application.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 104620b37..f47cb0ce9 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Application do import Cachex.Spec use Application + require Logger @name Mix.Project.config()[:name] @version Mix.Project.config()[:version] @@ -81,7 +82,7 @@ defmodule Pleroma.Application do {:ok, modules, _warnings} -> if @env != :test do Enum.each(modules, fn mod -> - IO.puts("Custom module loaded: #{inspect(mod)}") + Logger.info("Custom module loaded: #{inspect(mod)}") end) end -- cgit v1.2.3 From 78299ab18205b0bbaf521640e188a862ca27aa61 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 9 Dec 2019 19:12:24 +0700 Subject: Set Plug.Logger to log at `:debug` level --- lib/pleroma/web/endpoint.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 49735b5c2..5fcce7ca2 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -59,7 +59,7 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Plugs.TrailingFormatPlug) plug(Plug.RequestId) - plug(Plug.Logger) + plug(Plug.Logger, log: :debug) plug( Plug.Parsers, -- cgit v1.2.3 From b7a57d8e388a03d7d92248aa8c583365bde9d0b1 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 10 Dec 2019 00:38:01 +0700 Subject: Use Pleroma.Utils.compile_dir/1 in Pleroma.HTML.compile_scrubbers/0 --- lib/pleroma/html.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 2cae29f35..11513106e 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -10,9 +10,7 @@ defmodule Pleroma.HTML do dir = Path.join(:code.priv_dir(:pleroma), "scrubbers") dir - |> File.ls!() - |> Enum.map(&Path.join(dir, &1)) - |> Kernel.ParallelCompiler.compile() + |> Pleroma.Utils.compile_dir() |> case do {:error, _errors, _warnings} -> raise "Compiling scrubbers failed" -- cgit v1.2.3 From a37bd5c25587528b9f7a8ac1d148f6a4eb171769 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 10 Dec 2019 15:08:57 +0700 Subject: Change log level --- lib/pleroma/object/fetcher.ex | 2 +- lib/pleroma/web/activity_pub/publisher.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 4d71c91a8..a1bde90f1 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -154,7 +154,7 @@ defmodule Pleroma.Object.Fetcher do end def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do - Logger.info("Fetching object #{id} via AP") + Logger.debug("Fetching object #{id} via AP") date = Pleroma.Signature.signed_date() diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 4ea37fc7b..e834f43ad 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -47,7 +47,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do * `id`: the ActivityStreams URI of the message """ def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do - Logger.info("Federating #{id} to #{inbox}") + Logger.debug("Federating #{id} to #{inbox}") %{host: host, path: path} = URI.parse(inbox) digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64()) -- cgit v1.2.3 From ee6805850c8a86105b7f16d0510cf8465ba24452 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 11 Dec 2019 17:46:07 +0700 Subject: Set log level to debug for not important messages --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 6 +++--- lib/pleroma/web/activity_pub/mrf/drop_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex | 2 +- lib/pleroma/web/activity_pub/publisher.ex | 2 +- lib/pleroma/web/federator/federator.ex | 8 ++++---- lib/pleroma/web/federator/publisher.ex | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index dec5da0d3..5059e3984 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -257,7 +257,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do # only accept relayed Creates def inbox(conn, %{"type" => "Create"} = params) do - Logger.info( + Logger.debug( "Signature missing or not from author, relayed Create message, fetching object from source" ) @@ -270,11 +270,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do headers = Enum.into(conn.req_headers, %{}) if String.contains?(headers["signature"], params["actor"]) do - Logger.info( + Logger.debug( "Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!" ) - Logger.info(inspect(conn.req_headers)) + Logger.debug(inspect(conn.req_headers)) end json(conn, dgettext("errors", "error")) diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex index f7831bc3e..4a5709974 100644 --- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do @impl true def filter(object) do - Logger.info("REJECTING #{inspect(object)}") + Logger.debug("REJECTING #{inspect(object)}") {:reject, object} end diff --git a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex index 26b8539fe..df774b0f7 100644 --- a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex @@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do ] def perform(:prefetch, url) do - Logger.info("Prefetching #{inspect(url)}") + Logger.debug("Prefetching #{inspect(url)}") url |> MediaProxy.url() diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index e834f43ad..aeaddff64 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -223,7 +223,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do public = is_public?(activity) if public && Config.get([:instance, :allow_relay]) do - Logger.info(fn -> "Relaying #{activity.data["id"]} out" end) + Logger.debug(fn -> "Relaying #{activity.data["id"]} out" end) Relay.publish(activity) end diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index e8a56ebd7..f506a7d24 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -58,7 +58,7 @@ defmodule Pleroma.Web.Federator do end def perform(:incoming_ap_doc, params) do - Logger.info("Handling incoming AP activity") + Logger.debug("Handling incoming AP activity") params = Utils.normalize_params(params) @@ -71,13 +71,13 @@ defmodule Pleroma.Web.Federator do {:ok, activity} else %Activity{} -> - Logger.info("Already had #{params["id"]}") + Logger.debug("Already had #{params["id"]}") :error _e -> # Just drop those for now - Logger.info("Unhandled activity") - Logger.info(Jason.encode!(params, pretty: true)) + Logger.debug("Unhandled activity") + Logger.debug(Jason.encode!(params, pretty: true)) :error end end diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index fb9b26649..1d045c644 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -47,7 +47,7 @@ defmodule Pleroma.Web.Federator.Publisher do Config.get([:instance, :federation_publisher_modules]) |> Enum.each(fn module -> if module.is_representable?(activity) do - Logger.info("Publishing #{activity.data["id"]} using #{inspect(module)}") + Logger.debug("Publishing #{activity.data["id"]} using #{inspect(module)}") module.publish(user, activity) end end) -- cgit v1.2.3 From 02c3031e9985892bb698436105b93ac5481b6984 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Fri, 13 Dec 2019 11:14:11 -0800 Subject: Don't log when users or objects are deleted. --- lib/pleroma/object/fetcher.ex | 3 +++ lib/pleroma/web/activity_pub/activity_pub.ex | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 4d71c91a8..9bc7b0210 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -117,6 +117,9 @@ defmodule Pleroma.Object.Fetcher do {:error, %Tesla.Mock.Error{}} -> nil + {:error, "Object has been deleted"} -> + nil + e -> Logger.error("Error while fetching #{id}: #{inspect(e)}") nil diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 16e6b0057..ac76eb7d8 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1377,6 +1377,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do data <- maybe_update_follow_information(data) do {:ok, data} else + {:error, "Object has been deleted"} = e -> + Logger.debug("Could not decode user at fetch #{ap_id}, #{inspect(e)}") + {:error, e} + e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}") {:error, e} -- cgit v1.2.3 From 7973cbdb9fa9120306cb5a265a477eeccd315ee6 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sun, 15 Dec 2019 22:32:42 +0300 Subject: OAuthScopesPlug: disallowed nil token (unless with :fallback option). WIP: controller tests modification: OAuth scopes usage. --- lib/pleroma/plugs/oauth_scopes_plug.ex | 9 ++-- lib/pleroma/user.ex | 6 +-- .../controllers/emoji_api_controller.ex | 2 +- .../controllers/pleroma_api_controller.ex | 9 +++- .../web/twitter_api/controllers/util_controller.ex | 57 ++++++++++++++-------- 5 files changed, 53 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/oauth_scopes_plug.ex b/lib/pleroma/plugs/oauth_scopes_plug.ex index 174a8389c..07c0f7fdb 100644 --- a/lib/pleroma/plugs/oauth_scopes_plug.ex +++ b/lib/pleroma/plugs/oauth_scopes_plug.ex @@ -18,16 +18,13 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do token = assigns[:token] scopes = transform_scopes(scopes, options) - matched_scopes = token && filter_descendants(scopes, token.scopes) + matched_scopes = (token && filter_descendants(scopes, token.scopes)) || [] cond do - is_nil(token) -> - maybe_perform_instance_privacy_check(conn, options) - - op == :| && Enum.any?(matched_scopes) -> + token && op == :| && Enum.any?(matched_scopes) -> conn - op == :& && matched_scopes == scopes -> + token && op == :& && matched_scopes == scopes -> conn options[:fallback] == :proceed_unauthenticated -> diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 706aee2ff..021a542b3 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1855,9 +1855,9 @@ defmodule Pleroma.User do ]) with {:ok, updated_user} <- update_and_set_cache(changeset) do - if user.is_admin && !updated_user.is_admin do - # Tokens & authorizations containing any admin scopes must be revoked (revoking all). - # This is an extra safety measure (tokens' admin scopes won't be accepted for non-admins). + if user.is_admin != updated_user.is_admin do + # Admin status change results in change of accessible OAuth scopes, and instead of changing + # already issued tokens we revoke them, requiring user to sign in again global_sign_out(user) end diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index 69dfa92e3..0bbf84fd3 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -52,7 +52,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do @doc """ Lists the packs available on the instance as JSON. - The information is public and does not require authentification. The format is + The information is public and does not require authentication. The format is a map of "pack directory name" to pack.json contents. """ def list_packs(conn, _params) do diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 8fed3f5bb..772c535a4 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -22,7 +22,14 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do plug( OAuthScopesPlug, - %{scopes: ["read:statuses"]} when action in [:conversation, :conversation_statuses] + %{scopes: ["read:statuses"]} + when action in [:conversation, :conversation_statuses, :emoji_reactions_by] + ) + + plug( + OAuthScopesPlug, + %{scopes: ["write:statuses"]} + when action in [:react_with_emoji, :unreact_with_emoji] ) plug( diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 2305bb413..849783d4a 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -22,7 +22,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do plug( OAuthScopesPlug, %{scopes: ["follow", "write:follows"]} - when action in [:do_remote_follow, :follow_import] + when action == :follow_import + ) + + # Note: follower can submit the form (with password auth) not being signed in (having no token) + plug( + OAuthScopesPlug, + %{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]} + when action == :do_remote_follow ) plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks_import) @@ -112,6 +119,28 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) + when not is_nil(user) do + with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, + {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do + conn + |> render("followed.html", %{error: false}) + else + # Was already following user + {:error, "Could not follow user:" <> _rest} -> + render(conn, "followed.html", %{error: "Error following account"}) + + {:fetch_user, error} -> + Logger.debug("Remote follow failed with error #{inspect(error)}") + render(conn, "followed.html", %{error: "Could not find user"}) + + e -> + Logger.debug("Remote follow failed with error #{inspect(e)}") + render(conn, "followed.html", %{error: "Something went wrong."}) + end + end + + # Note: "id" is the id of followee user, disregard incorrect placing under "authorization" def do_remote_follow(conn, %{ "authorization" => %{"name" => username, "password" => password, "id" => id} }) do @@ -145,24 +174,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end - def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do - with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, - {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do - conn - |> render("followed.html", %{error: false}) - else - # Was already following user - {:error, "Could not follow user:" <> _rest} -> - render(conn, "followed.html", %{error: "Error following account"}) - - {:fetch_user, error} -> - Logger.debug("Remote follow failed with error #{inspect(error)}") - render(conn, "followed.html", %{error: "Could not find user"}) + def do_remote_follow(%{assigns: %{user: nil}} = conn, _) do + render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."}) + end - e -> - Logger.debug("Remote follow failed with error #{inspect(e)}") - render(conn, "followed.html", %{error: "Something went wrong."}) - end + def do_remote_follow(conn, _) do + render(conn, "followed.html", %{error: "Something went wrong."}) end def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do @@ -345,7 +362,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def delete_account(%{assigns: %{user: user}} = conn, params) do - case CommonAPI.Utils.confirm_current_password(user, params["password"]) do + password = params["password"] || "" + + case CommonAPI.Utils.confirm_current_password(user, password) do {:ok, user} -> User.delete(user) json(conn, %{status: "success"}) -- cgit v1.2.3 From 6c39fa20b191f985a2be704089c20acbcfe0035a Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 17 Dec 2019 17:00:46 +0700 Subject: Add support for `account_id` param to filter notifications by the account --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index b1816370e..6c13d4df6 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -56,6 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do user |> Notification.for_user_query(options) |> restrict(:exclude_types, options) + |> restrict(:account_id, options) |> Pagination.fetch_paginated(params) end @@ -71,7 +72,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do exclude_visibilities: {:array, :string}, reblogs: :boolean, with_muted: :boolean, - with_move: :boolean + with_move: :boolean, + account_id: :string } changeset = cast({%{}, param_types}, params, Map.keys(param_types)) @@ -88,5 +90,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do |> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data)) end + defp restrict(query, :account_id, %{account_id: account_id}) do + case User.get_cached_by_id(account_id) do + %{ap_id: ap_id} -> where(query, [n, a], a.actor == ^ap_id) + _ -> where(query, [n, a], a.actor == "fake ap id") + end + end + defp restrict(query, _, _), do: query end -- cgit v1.2.3 From d2f1c4f658a8c995716aee3876cb46a0f48f99cb Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Tue, 17 Dec 2019 16:16:21 +0100 Subject: Add ActivityPub Object Event type support Adds Event support in the same way Video objects are handled, with the name of the object as message header. Signed-off-by: Thomas Citharel --- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- lib/pleroma/web/activity_pub/utils.ex | 11 ++++++++++- lib/pleroma/web/mastodon_api/views/status_view.ex | 3 ++- lib/pleroma/web/twitter_api/controllers/util_controller.ex | 3 ++- 4 files changed, 15 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index ecba27bef..3fa789d53 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -397,7 +397,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do %{"type" => "Create", "object" => %{"type" => objtype} = object} = data, options ) - when objtype in ["Article", "Note", "Video", "Page", "Question", "Answer"] do + when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer"] do actor = Containment.get_actor(data) data = diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index e87d09134..db7084246 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -22,7 +22,16 @@ defmodule Pleroma.Web.ActivityPub.Utils do require Logger require Pleroma.Constants - @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer", "Audio"] + @supported_object_types [ + "Article", + "Note", + "Event", + "Video", + "Page", + "Question", + "Answer", + "Audio" + ] @strip_status_report_states ~w(closed resolved) @supported_report_states ~w(open closed resolved) @valid_visibilities ~w(public unlisted private direct) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index a0257dfa6..e9590224b 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -421,7 +421,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do end end - def render_content(%{data: %{"type" => "Video"}} = object) do + def render_content(%{data: %{"type" => object_type}} = object) + when object_type in ["Video", "Event"] do with name when not is_nil(name) and name != "" <- object.data["name"] do "

#{name}

#{object.data["content"]}" else diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 2305bb413..799dd17ae 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -104,7 +104,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do defp is_status?(acct) do case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do - {:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] -> + {:ok, %{"type" => type}} + when type in ["Article", "Event", "Note", "Video", "Page", "Question"] -> true _ -> -- cgit v1.2.3 From b53573a837e606ef3536ec338510cadacab55d7c Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 17 Dec 2019 22:13:45 +0300 Subject: add tag feeds --- lib/pleroma/web/controller_helper.ex | 7 +++++-- lib/pleroma/web/feed/feed_view.ex | 24 ++++++++++++++++++++++ lib/pleroma/web/feed/tag_controller.ex | 20 ++++++++++-------- lib/pleroma/web/feed/user_controller.ex | 10 ++++----- lib/pleroma/web/metadata/utils.ex | 11 ++++++++-- .../web/templates/feed/feed/_tag_activity.xml.eex | 15 ++++++++++++++ lib/pleroma/web/templates/feed/feed/tag.xml.eex | 21 +++++++++++-------- 7 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex (limited to 'lib') diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index 9a4e322c9..e3d7a465b 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -76,8 +76,7 @@ defmodule Pleroma.Web.ControllerHelper do end end - def try_render(conn, target, params) - when is_binary(target) do + def try_render(conn, target, params) when is_binary(target) do case render(conn, target, params) do nil -> render_error(conn, :not_implemented, "Can't display this activity") res -> res @@ -87,4 +86,8 @@ defmodule Pleroma.Web.ControllerHelper do def try_render(conn, _, _) do render_error(conn, :not_implemented, "Can't display this activity") end + + @spec put_in_if_exist(map(), atom() | String.t(), any) :: map() + def put_in_if_exist(map, _key, nil), do: map + def put_in_if_exist(map, key, value), do: put_in(map, key, value) end diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index bb1332fd3..2e7db1ebb 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -13,6 +13,15 @@ defmodule Pleroma.Web.Feed.FeedView do require Pleroma.Constants + @spec pub_date(String.t() | DateTime.t()) :: String.t() + def pub_date(date) when is_binary(date) do + date + |> Timex.parse!("{ISO:Extended}") + |> pub_date + end + + def pub_date(%DateTime{} = date), do: Timex.format!(date, "{RFC822}") + def prepare_activity(activity) do object = activity_object(activity) @@ -28,6 +37,17 @@ defmodule Pleroma.Web.Feed.FeedView do |> NaiveDateTime.to_iso8601() end + def feed_logo do + case Pleroma.Config.get([:feed, :logo]) do + nil -> + "#{Pleroma.Web.base_url()}/static/logo.png" + + logo -> + "#{Pleroma.Web.base_url()}#{logo}" + end + |> MediaProxy.url() + end + def logo(user) do user |> User.avatar_url() @@ -40,6 +60,8 @@ defmodule Pleroma.Web.Feed.FeedView do def activity_title(%{data: %{"content" => content}}, opts \\ %{}) do content + |> Pleroma.Web.Metadata.Utils.scrub_html() + |> Pleroma.Emoji.Formatter.demojify() |> Formatter.truncate(opts[:max_length], opts[:omission]) |> escape() end @@ -50,6 +72,8 @@ defmodule Pleroma.Web.Feed.FeedView do |> escape() end + def activity_content(_), do: "" + def activity_context(activity), do: activity.data["context"] def attachment_href(attachment) do diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex index 66abc186b..97ce147de 100644 --- a/lib/pleroma/web/feed/tag_controller.ex +++ b/lib/pleroma/web/feed/tag_controller.ex @@ -9,20 +9,24 @@ defmodule Pleroma.Web.Feed.TagController do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.Feed.FeedView - def feed(conn, %{"tag" => tag} = params) do + import Pleroma.Web.ControllerHelper, only: [put_in_if_exist: 3] + + def feed(conn, %{"tag" => raw_tag} = params) do + tag = parse_tag(raw_tag) + activities = - %{ - "type" => ["Create"], - "whole_db" => true, - "tag" => parse_tag(tag) - } - |> Map.merge(Map.take(params, ["max_id"])) + %{"type" => ["Create"], "whole_db" => true, "tag" => tag} + |> put_in_if_exist("max_id", params["max_id"]) |> ActivityPub.fetch_public_activities() conn |> put_resp_content_type("application/atom+xml") |> put_view(FeedView) - |> render("tag.xml", activities: activities, feed_config: Config.get([:feed])) + |> render("tag.xml", + activities: activities, + tag: tag, + feed_config: Config.get([:feed]) + ) end defp parse_tag(raw_tag) when is_binary(raw_tag) do diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex index e5d8427ce..cf04fd497 100644 --- a/lib/pleroma/web/feed/user_controller.ex +++ b/lib/pleroma/web/feed/user_controller.ex @@ -11,6 +11,8 @@ defmodule Pleroma.Web.Feed.UserController do alias Pleroma.Web.ActivityPub.ActivityPubController alias Pleroma.Web.Feed.FeedView + import Pleroma.Web.ControllerHelper, only: [put_in_if_exist: 3] + plug(Pleroma.Plugs.SetFormatPlug when action in [:feed_redirect]) action_fallback(:errors) @@ -35,12 +37,8 @@ defmodule Pleroma.Web.Feed.UserController do def feed(conn, %{"nickname" => nickname} = params) do with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do activities = - %{ - "type" => ["Create"], - "whole_db" => true, - "actor_id" => user.ap_id - } - |> Map.merge(Map.take(params, ["max_id"])) + %{"type" => ["Create"], "whole_db" => true, "actor_id" => user.ap_id} + |> put_in_if_exist("max_id", params["max_id"]) |> ActivityPub.fetch_public_activities() conn diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index 382ecf426..c0dae1b7e 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -19,15 +19,22 @@ defmodule Pleroma.Web.Metadata.Utils do end def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do + content + |> scrub_html + |> Emoji.Formatter.demojify() + |> Formatter.truncate(max_length) + end + + def scrub_html(content) when is_binary(content) do content # html content comes from DB already encoded, decode first and scrub after |> HtmlEntities.decode() |> String.replace(~r//, " ") |> HTML.strip_tags() - |> Emoji.Formatter.demojify() - |> Formatter.truncate(max_length) end + def scrub_html(content), do: content + def attachment_url(url) do MediaProxy.url(url) end diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex new file mode 100644 index 000000000..295574df1 --- /dev/null +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex @@ -0,0 +1,15 @@ + + <%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %> + + + <%= activity_context(@activity) %> + <%= activity_context(@activity) %> + <%= pub_date(@data["published"]) %> + + <%= activity_content(@object) %> + <%= for attachment <- @data["attachment"] || [] do %> + + <% end %> + + + diff --git a/lib/pleroma/web/templates/feed/feed/tag.xml.eex b/lib/pleroma/web/templates/feed/feed/tag.xml.eex index 52b1d7b7d..eeda01a04 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.xml.eex @@ -1,10 +1,15 @@ - + + - TAGS - + + #<%= @tag %> + These are public toots tagged with #<%= @tag %>. You can interact with them if you have an account anywhere in the fediverse. + <%= '#{tag_feed_url(@conn, :feed, @tag)}.rss' %> + <%= feed_logo() %> + 2b90d9 + <%= for activity <- @activities do %> + <%= render @view_module, "_tag_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> + <% end %> + + -- cgit v1.2.3 From 404a9ccb9a220f3f52ee03bd69bd3746d95794cc Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 18 Dec 2019 23:11:42 +0300 Subject: Stats: return status counts by scope --- lib/pleroma/stats.ex | 72 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 8154a09b7..c90e8f409 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -3,11 +3,15 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Stats do + use GenServer + import Ecto.Query + + alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User - use GenServer + require Pleroma.Constants @interval 1000 * 60 * 60 @@ -56,7 +60,7 @@ defmodule Pleroma.Stats do %{peers: [], stats: %{}} end - defp get_stat_data do + def get_stat_data do peers = from( u in User, @@ -68,13 +72,71 @@ defmodule Pleroma.Stats do domain_count = Enum.count(peers) - status_count = Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count) - user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id) %{ peers: peers, - stats: %{domain_count: domain_count, status_count: status_count, user_count: user_count} + stats: %{domain_count: domain_count, status_count: status_count(), user_count: user_count} } end + + defp status_count do + %{ + all: get_all_statuses_count(), + public: public_statuses_query() |> Repo.aggregate(:count, :id), + unlisted: unlisted_statuses_query() |> Repo.aggregate(:count, :id), + direct: direct_statuses_query() |> Repo.aggregate(:count, :id), + private: private_statuses_query() |> Repo.aggregate(:count, :id) + } + end + + defp get_all_statuses_count do + Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count) + end + + def public_statuses_query do + from(o in Object, + where: fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()) + ) + end + + def unlisted_statuses_query do + from(o in Object, + where: not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()), + where: fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public()) + ) + end + + def direct_statuses_query do + private_statuses_ids = from(p in private_statuses_query(), select: p.id) |> Repo.all() + + from(o in Object, + where: + fragment( + "? \\? 'directMessage' AND (?->>'directMessage')::boolean = true", + o.data, + o.data + ) or + (not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()) and + not fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public()) and + o.id not in ^private_statuses_ids) + ) + end + + def private_statuses_query do + from(o in subquery(recipients_query()), + where: ilike(o.recipients, "%/followers%") + ) + end + + defp recipients_query do + from(o in Object, + select: %{ + id: o.id, + recipients: fragment("jsonb_array_elements_text((?)->'to')", o.data) + }, + where: not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()), + where: not fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public()) + ) + end end -- cgit v1.2.3 From 432b3067d4c62cd27e35f0b6e7bdc61da63310b9 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 19 Dec 2019 19:25:23 +0700 Subject: Do not crash when remote user follower and following counters are hidden --- lib/pleroma/web/activity_pub/activity_pub.ex | 40 +++++++++++----------------- 1 file changed, 16 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 16e6b0057..60c9e7e64 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1298,28 +1298,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def fetch_follow_information_for_user(user) do with {:ok, following_data} <- Fetcher.fetch_and_contain_remote_object_from_id(user.following_address), - following_count when is_integer(following_count) <- following_data["totalItems"], {:ok, hide_follows} <- collection_private(following_data), {:ok, followers_data} <- Fetcher.fetch_and_contain_remote_object_from_id(user.follower_address), - followers_count when is_integer(followers_count) <- followers_data["totalItems"], {:ok, hide_followers} <- collection_private(followers_data) do {:ok, %{ hide_follows: hide_follows, - follower_count: followers_count, - following_count: following_count, + follower_count: normalize_counter(followers_data["totalItems"]), + following_count: normalize_counter(following_data["totalItems"]), hide_followers: hide_followers }} else - {:error, _} = e -> - e - - e -> - {:error, e} + {:error, _} = e -> e + e -> {:error, e} end end + defp normalize_counter(counter) when is_integer(counter), do: counter + defp normalize_counter(_), do: 0 + defp maybe_update_follow_information(data) do with {:enabled, true} <- {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])}, @@ -1339,24 +1337,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + defp collection_private(%{"first" => %{"type" => type}}) + when type in ["CollectionPage", "OrderedCollectionPage"], + do: {:ok, false} + defp collection_private(%{"first" => first}) do - if is_map(first) and - first["type"] in ["CollectionPage", "OrderedCollectionPage"] do + with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <- + Fetcher.fetch_and_contain_remote_object_from_id(first) do {:ok, false} else - with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <- - Fetcher.fetch_and_contain_remote_object_from_id(first) do - {:ok, false} - else - {:error, {:ok, %{status: code}}} when code in [401, 403] -> - {:ok, true} - - {:error, _} = e -> - e - - e -> - {:error, e} - end + {:error, {:ok, %{status: code}}} when code in [401, 403] -> {:ok, true} + {:error, _} = e -> e + e -> {:error, e} end end -- cgit v1.2.3 From 34d85f8a5473fe0f85e8a8e9e8f58e40b3964ba4 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 19 Dec 2019 20:45:44 +0700 Subject: Return 404 if account to filter notifications from is not found --- .../mastodon_api/controllers/notification_controller.ex | 17 +++++++++++++++++ lib/pleroma/web/mastodon_api/mastodon_api.ex | 11 ++++------- 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex index 16759be6a..f2508aca4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex @@ -23,6 +23,23 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) # GET /api/v1/notifications + def index(conn, %{"account_id" => account_id} = params) do + case Pleroma.User.get_cached_by_id(account_id) do + %{ap_id: account_ap_id} -> + params = + params + |> Map.delete("account_id") + |> Map.put("account_ap_id", account_ap_id) + + index(conn, params) + + _ -> + conn + |> put_status(:not_found) + |> json(%{"error" => "Account is not found"}) + end + end + def index(%{assigns: %{user: user}} = conn, params) do notifications = MastodonAPI.get_notifications(user, params) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 6c13d4df6..390a2b190 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -56,7 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do user |> Notification.for_user_query(options) |> restrict(:exclude_types, options) - |> restrict(:account_id, options) + |> restrict(:account_ap_id, options) |> Pagination.fetch_paginated(params) end @@ -73,7 +73,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do reblogs: :boolean, with_muted: :boolean, with_move: :boolean, - account_id: :string + account_ap_id: :string } changeset = cast({%{}, param_types}, params, Map.keys(param_types)) @@ -90,11 +90,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do |> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data)) end - defp restrict(query, :account_id, %{account_id: account_id}) do - case User.get_cached_by_id(account_id) do - %{ap_id: ap_id} -> where(query, [n, a], a.actor == ^ap_id) - _ -> where(query, [n, a], a.actor == "fake ap id") - end + defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do + where(query, [n, a], a.actor == ^account_ap_id) end defp restrict(query, _, _), do: query -- cgit v1.2.3 From 455e072d27f28c39050b2dc24b346a8f2ef30f90 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Thu, 19 Dec 2019 17:23:27 +0300 Subject: [#2068] Introduced proper OAuth tokens usage to controller tests. --- lib/pleroma/web/masto_fe_controller.ex | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex index ca261ad6e..9f7e4943c 100644 --- a/lib/pleroma/web/masto_fe_controller.ex +++ b/lib/pleroma/web/masto_fe_controller.ex @@ -20,18 +20,21 @@ defmodule Pleroma.Web.MastoFEController do plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :index) @doc "GET /web/*path" - def index(%{assigns: %{user: user}} = conn, _params) do - token = get_session(conn, :oauth_token) + def index(%{assigns: %{user: user, token: token}} = conn, _params) + when not is_nil(user) and not is_nil(token) do + conn + |> put_layout(false) + |> render("index.html", + token: token.token, + user: user, + custom_emojis: Pleroma.Emoji.get_all() + ) + end - if user && token do - conn - |> put_layout(false) - |> render("index.html", token: token, user: user, custom_emojis: Pleroma.Emoji.get_all()) - else - conn - |> put_session(:return_to, conn.request_path) - |> redirect(to: "/web/login") - end + def index(conn, _params) do + conn + |> put_session(:return_to, conn.request_path) + |> redirect(to: "/web/login") end @doc "GET /web/manifest.json" -- cgit v1.2.3 From 5fc84552d311efd606f66775c55862b3d11ad258 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 19 Dec 2019 19:52:55 +0300 Subject: Fix all count --- lib/pleroma/stats.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index c90e8f409..97e8b1990 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -82,7 +82,7 @@ defmodule Pleroma.Stats do defp status_count do %{ - all: get_all_statuses_count(), + all: all_statuses_query() |> Repo.aggregate(:count, :id), public: public_statuses_query() |> Repo.aggregate(:count, :id), unlisted: unlisted_statuses_query() |> Repo.aggregate(:count, :id), direct: direct_statuses_query() |> Repo.aggregate(:count, :id), @@ -90,8 +90,8 @@ defmodule Pleroma.Stats do } end - defp get_all_statuses_count do - Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count) + defp all_statuses_query do + from(o in Object, where: fragment("(?)->>'type' = 'Note'", o.data)) end def public_statuses_query do -- cgit v1.2.3 From 7bd0bca2abadb96aa13ace36b968d57872681f7a Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 20 Dec 2019 16:33:44 +0300 Subject: fixed remote follow --- lib/pleroma/web/activity_pub/publisher.ex | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 4073d3d63..0cc8fab27 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -264,6 +264,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do "rel" => "self", "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", "href" => user.ap_id + }, + %{ + "rel" => "http://ostatus.org/schema/1.0/subscribe", + "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}" } ] end -- cgit v1.2.3 From 06ae56a3ae93c494f9c5d15b097d75c6ab7fcc29 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 20 Dec 2019 16:32:04 -0600 Subject: Posts without media attachments should get the Summary TwitterCard --- lib/pleroma/web/metadata/twitter_card.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/metadata/twitter_card.ex b/lib/pleroma/web/metadata/twitter_card.ex index d6a6049b3..67419a666 100644 --- a/lib/pleroma/web/metadata/twitter_card.ex +++ b/lib/pleroma/web/metadata/twitter_card.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do if attachments == [] or Metadata.activity_nsfw?(object) do [ image_tag(user), - {:meta, [property: "twitter:card", content: "summary_large_image"], []} + {:meta, [property: "twitter:card", content: "summary"], []} ] else attachments -- cgit v1.2.3 From e71a13ad57d2604b45c0beb278f47d25c284783a Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sat, 21 Dec 2019 11:41:19 +0000 Subject: Revert "Merge branch 'feature/status-counts-by-scope' into 'develop'" This reverts merge request !2076 --- lib/pleroma/stats.ex | 72 ++++------------------------------------------------ 1 file changed, 5 insertions(+), 67 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 97e8b1990..8154a09b7 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -3,15 +3,11 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Stats do - use GenServer - import Ecto.Query - - alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User - require Pleroma.Constants + use GenServer @interval 1000 * 60 * 60 @@ -60,7 +56,7 @@ defmodule Pleroma.Stats do %{peers: [], stats: %{}} end - def get_stat_data do + defp get_stat_data do peers = from( u in User, @@ -72,71 +68,13 @@ defmodule Pleroma.Stats do domain_count = Enum.count(peers) + status_count = Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count) + user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id) %{ peers: peers, - stats: %{domain_count: domain_count, status_count: status_count(), user_count: user_count} + stats: %{domain_count: domain_count, status_count: status_count, user_count: user_count} } end - - defp status_count do - %{ - all: all_statuses_query() |> Repo.aggregate(:count, :id), - public: public_statuses_query() |> Repo.aggregate(:count, :id), - unlisted: unlisted_statuses_query() |> Repo.aggregate(:count, :id), - direct: direct_statuses_query() |> Repo.aggregate(:count, :id), - private: private_statuses_query() |> Repo.aggregate(:count, :id) - } - end - - defp all_statuses_query do - from(o in Object, where: fragment("(?)->>'type' = 'Note'", o.data)) - end - - def public_statuses_query do - from(o in Object, - where: fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()) - ) - end - - def unlisted_statuses_query do - from(o in Object, - where: not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()), - where: fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public()) - ) - end - - def direct_statuses_query do - private_statuses_ids = from(p in private_statuses_query(), select: p.id) |> Repo.all() - - from(o in Object, - where: - fragment( - "? \\? 'directMessage' AND (?->>'directMessage')::boolean = true", - o.data, - o.data - ) or - (not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()) and - not fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public()) and - o.id not in ^private_statuses_ids) - ) - end - - def private_statuses_query do - from(o in subquery(recipients_query()), - where: ilike(o.recipients, "%/followers%") - ) - end - - defp recipients_query do - from(o in Object, - select: %{ - id: o.id, - recipients: fragment("jsonb_array_elements_text((?)->'to')", o.data) - }, - where: not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()), - where: not fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public()) - ) - end end -- cgit v1.2.3 From 5b8415601346447b9a66b1eabfc7538191892a76 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 20 Dec 2019 16:34:14 +0300 Subject: moved remote follow in separate controller --- lib/pleroma/web/router.ex | 4 +- .../twitter_api/remote_follow/follow.html.eex | 11 +++ .../remote_follow/follow_login.html.eex | 14 +++ .../twitter_api/remote_follow/followed.html.eex | 6 ++ .../web/templates/twitter_api/util/follow.html.eex | 11 --- .../twitter_api/util/follow_login.html.eex | 14 --- .../templates/twitter_api/util/followed.html.eex | 6 -- .../controllers/remote_follow_controller.ex | 102 +++++++++++++++++++++ .../web/twitter_api/controllers/util_controller.ex | 91 ------------------ .../web/twitter_api/views/remote_follow_view.ex | 10 ++ 10 files changed, 145 insertions(+), 124 deletions(-) create mode 100644 lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex create mode 100644 lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex create mode 100644 lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex delete mode 100644 lib/pleroma/web/templates/twitter_api/util/follow.html.eex delete mode 100644 lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex delete mode 100644 lib/pleroma/web/templates/twitter_api/util/followed.html.eex create mode 100644 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex create mode 100644 lib/pleroma/web/twitter_api/views/remote_follow_view.ex (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f6c128283..9654ab8a3 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -229,9 +229,9 @@ defmodule Pleroma.Web.Router do pipe_through(:pleroma_html) post("/main/ostatus", UtilController, :remote_subscribe) - get("/ostatus_subscribe", UtilController, :remote_follow) + get("/ostatus_subscribe", RemoteFollowController, :follow) - post("/ostatus_subscribe", UtilController, :do_remote_follow) + post("/ostatus_subscribe", RemoteFollowController, :do_follow) end scope "/api/pleroma", Pleroma.Web.TwitterAPI do diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex new file mode 100644 index 000000000..5ba192cd7 --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex @@ -0,0 +1,11 @@ +<%= if @error == :error do %> +

Error fetching user

+<% else %> +

Remote follow

+ +

<%= @followee.nickname %>

+ <%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %> + <%= hidden_input f, :id, value: @followee.id %> + <%= submit "Authorize" %> + <% end %> +<% end %> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex new file mode 100644 index 000000000..df44988ee --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex @@ -0,0 +1,14 @@ +<%= if @error do %> +

<%= @error %>

+<% end %> +

Log in to follow

+

<%= @followee.nickname %>

+ +<%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %> +<%= text_input f, :name, placeholder: "Username", required: true %> +
+<%= password_input f, :password, placeholder: "Password", required: true %> +
+<%= hidden_input f, :id, value: @followee.id %> +<%= submit "Authorize" %> +<% end %> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex new file mode 100644 index 000000000..da473d502 --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex @@ -0,0 +1,6 @@ +<%= if @error do %> +

Error following account

+<% else %> +

Account followed!

+<% end %> + diff --git a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex deleted file mode 100644 index 06359fa6c..000000000 --- a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex +++ /dev/null @@ -1,11 +0,0 @@ -<%= if @error == :error do %> -

Error fetching user

-<% else %> -

Remote follow

- -

<%= @name %>

- <%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "user"], fn f -> %> - <%= hidden_input f, :id, value: @id %> - <%= submit "Authorize" %> - <% end %> -<% end %> diff --git a/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex deleted file mode 100644 index 4e3a2be67..000000000 --- a/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex +++ /dev/null @@ -1,14 +0,0 @@ -<%= if @error do %> -

<%= @error %>

-<% end %> -

Log in to follow

-

<%= @name %>

- -<%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "authorization"], fn f -> %> -<%= text_input f, :name, placeholder: "Username" %> -
-<%= password_input f, :password, placeholder: "Password" %> -
-<%= hidden_input f, :id, value: @id %> -<%= submit "Authorize" %> -<% end %> diff --git a/lib/pleroma/web/templates/twitter_api/util/followed.html.eex b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex deleted file mode 100644 index da473d502..000000000 --- a/lib/pleroma/web/templates/twitter_api/util/followed.html.eex +++ /dev/null @@ -1,6 +0,0 @@ -<%= if @error do %> -

Error following account

-<% else %> -

Account followed!

-<% end %> - diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex new file mode 100644 index 000000000..460a42566 --- /dev/null +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -0,0 +1,102 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do + use Pleroma.Web, :controller + + require Logger + + alias Pleroma.Activity + alias Pleroma.Object.Fetcher + alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.User + alias Pleroma.Web.Auth.Authenticator + alias Pleroma.Web.CommonAPI + + @status_types ["Article", "Event", "Note", "Video", "Page", "Question"] + + plug(OAuthScopesPlug, %{scopes: ["follow", "write:follows"]} when action in [:do_follow]) + + # GET /ostatus_subscribe + # + def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do + case is_status?(acct) do + true -> follow_status(conn, user, acct) + _ -> follow_account(conn, user, acct) + end + end + + defp follow_status(conn, _user, acct) do + with {:ok, object} <- Fetcher.fetch_object_from_id(acct), + %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object.data["id"]) do + redirect(conn, to: "/notice/#{activity_id}") + else + error -> + handle_follow_error(conn, error) + end + end + + defp follow_account(conn, user, acct) do + with {:ok, followee} <- User.get_or_fetch(acct) do + render(conn, follow_template(user), %{error: false, followee: followee, acct: acct}) + else + {:error, _reason} -> + render(conn, follow_template(user), %{error: :error}) + end + end + + defp follow_template(%User{} = _user), do: "follow.html" + defp follow_template(_), do: "follow_login.html" + + defp is_status?(acct) do + case Fetcher.fetch_and_contain_remote_object_from_id(acct) do + {:ok, %{"type" => type}} when type in @status_types -> + true + + _ -> + false + end + end + + # POST /ostatus_subscribe + # + def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do + with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, + {_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee}, + {:ok, _, _, _} <- CommonAPI.follow(user, followee) do + render(conn, "followed.html", %{error: false}) + else + error -> + handle_follow_error(conn, error) + end + end + + def do_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do + with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, + {:ok, _, _, _} <- CommonAPI.follow(user, followee) do + render(conn, "followed.html", %{error: false}) + else + error -> + handle_follow_error(conn, error) + end + end + + defp handle_follow_error(conn, {:auth, _, followee} = _) do + render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee}) + end + + defp handle_follow_error(conn, {:fetch_user, error} = _) do + Logger.debug("Remote follow failed with error #{inspect(error)}") + render(conn, "followed.html", %{error: "Could not find user"}) + end + + defp handle_follow_error(conn, {:error, "Could not follow user:" <> _} = _) do + render(conn, "followed.html", %{error: "Error following account"}) + end + + defp handle_follow_error(conn, error) do + Logger.debug("Remote follow failed with error #{inspect(error)}") + render(conn, "followed.html", %{error: "Something went wrong."}) + end +end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 799dd17ae..a61f891c7 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -7,12 +7,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do require Logger - alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Emoji alias Pleroma.Healthcheck alias Pleroma.Notification - alias Pleroma.Plugs.AuthenticationPlug alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.User alias Pleroma.Web @@ -77,95 +75,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end - def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do - if is_status?(acct) do - {:ok, object} = Pleroma.Object.Fetcher.fetch_object_from_id(acct) - %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"]) - redirect(conn, to: "/notice/#{activity_id}") - else - with {:ok, followee} <- User.get_or_fetch(acct) do - conn - |> render(follow_template(user), %{ - error: false, - acct: acct, - avatar: User.avatar_url(followee), - name: followee.nickname, - id: followee.id - }) - else - {:error, _reason} -> - render(conn, follow_template(user), %{error: :error}) - end - end - end - - defp follow_template(%User{} = _user), do: "follow.html" - defp follow_template(_), do: "follow_login.html" - - defp is_status?(acct) do - case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do - {:ok, %{"type" => type}} - when type in ["Article", "Event", "Note", "Video", "Page", "Question"] -> - true - - _ -> - false - end - end - - def do_remote_follow(conn, %{ - "authorization" => %{"name" => username, "password" => password, "id" => id} - }) do - with %User{} = followee <- User.get_cached_by_id(id), - {_, %User{} = user, _} <- {:auth, User.get_cached_by_nickname(username), followee}, - {_, true, _} <- { - :auth, - AuthenticationPlug.checkpw(password, user.password_hash), - followee - }, - {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do - conn - |> render("followed.html", %{error: false}) - else - # Was already following user - {:error, "Could not follow user:" <> _rest} -> - render(conn, "followed.html", %{error: "Error following account"}) - - {:auth, _, followee} -> - conn - |> render("follow_login.html", %{ - error: "Wrong username or password", - id: id, - name: followee.nickname, - avatar: User.avatar_url(followee) - }) - - e -> - Logger.debug("Remote follow failed with error #{inspect(e)}") - render(conn, "followed.html", %{error: "Something went wrong."}) - end - end - - def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do - with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, - {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do - conn - |> render("followed.html", %{error: false}) - else - # Was already following user - {:error, "Could not follow user:" <> _rest} -> - render(conn, "followed.html", %{error: "Error following account"}) - - {:fetch_user, error} -> - Logger.debug("Remote follow failed with error #{inspect(error)}") - render(conn, "followed.html", %{error: "Could not find user"}) - - e -> - Logger.debug("Remote follow failed with error #{inspect(e)}") - render(conn, "followed.html", %{error: "Something went wrong."}) - end - end - def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do with {:ok, _} <- Notification.read_one(user, notification_id) do json(conn, %{status: "success"}) diff --git a/lib/pleroma/web/twitter_api/views/remote_follow_view.ex b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex new file mode 100644 index 000000000..8f1f21bce --- /dev/null +++ b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.TwitterAPI.RemoteFollowView do + use Pleroma.Web, :view + import Phoenix.HTML.Form + + def avatar_url(user), do: Pleroma.User.avatar_url(user) +end -- cgit v1.2.3 From c9a44ec4a6f7b98145e2b192519dfa6933f430d0 Mon Sep 17 00:00:00 2001 From: Maksim Date: Sun, 22 Dec 2019 17:58:45 +0000 Subject: Apply suggestion to lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex --- lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index 460a42566..e5e52a7e8 100644 --- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -30,7 +30,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do defp follow_status(conn, _user, acct) do with {:ok, object} <- Fetcher.fetch_object_from_id(acct), %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object.data["id"]) do - redirect(conn, to: "/notice/#{activity_id}") + redirect(conn, to: o_status_path(conn, :notice, activity_id)) else error -> handle_follow_error(conn, error) -- cgit v1.2.3 From 4c505bc615b0e698db4f6d16c3b1f0b159f30e02 Mon Sep 17 00:00:00 2001 From: Maksim Date: Sun, 22 Dec 2019 17:58:54 +0000 Subject: Apply suggestion to lib/pleroma/web/twitter_api/views/remote_follow_view.ex --- lib/pleroma/web/twitter_api/views/remote_follow_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/views/remote_follow_view.ex b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex index 8f1f21bce..fb6109906 100644 --- a/lib/pleroma/web/twitter_api/views/remote_follow_view.ex +++ b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex @@ -6,5 +6,5 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowView do use Pleroma.Web, :view import Phoenix.HTML.Form - def avatar_url(user), do: Pleroma.User.avatar_url(user) + defdelegate avatar_url(user), to: Pleroma.User.avatar_url end -- cgit v1.2.3 From bdd71669da43698716be6494528b6e1813d0cd3d Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Sun, 22 Dec 2019 21:17:19 +0300 Subject: update test --- lib/pleroma/web/twitter_api/views/remote_follow_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/views/remote_follow_view.ex b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex index fb6109906..d469c4726 100644 --- a/lib/pleroma/web/twitter_api/views/remote_follow_view.ex +++ b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex @@ -6,5 +6,5 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowView do use Pleroma.Web, :view import Phoenix.HTML.Form - defdelegate avatar_url(user), to: Pleroma.User.avatar_url + defdelegate avatar_url(user), to: Pleroma.User end -- cgit v1.2.3 From 385356aad0dd7eac0695bb1597ba1e52b5f17b40 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 24 Dec 2019 20:45:46 +0300 Subject: fix oauth scopes for AdminApi#reports_update --- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index c8abeff06..ddae139c6 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -66,7 +66,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, %{scopes: ["write:reports"], admin: true} - when action in [:report_update_state, :report_respond] + when action in [:reports_update] ) plug( -- cgit v1.2.3 From 933dc120438d14502e4bc4c29db904114fb6e438 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 25 Dec 2019 15:12:43 +0300 Subject: added code of mr#2067 --- .../controllers/remote_follow_controller.ex | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index e5e52a7e8..e0d4d5632 100644 --- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -16,7 +16,12 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do @status_types ["Article", "Event", "Note", "Video", "Page", "Question"] - plug(OAuthScopesPlug, %{scopes: ["follow", "write:follows"]} when action in [:do_follow]) + # Note: follower can submit the form (with password auth) not being signed in (having no token) + plug( + OAuthScopesPlug, + %{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]} + when action in [:do_follow] + ) # GET /ostatus_subscribe # @@ -61,9 +66,8 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do # POST /ostatus_subscribe # - def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do + def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, - {_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee}, {:ok, _, _, _} <- CommonAPI.follow(user, followee) do render(conn, "followed.html", %{error: false}) else @@ -72,8 +76,9 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do end end - def do_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do + def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, + {_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee}, {:ok, _, _, _} <- CommonAPI.follow(user, followee) do render(conn, "followed.html", %{error: false}) else @@ -82,6 +87,11 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do end end + def do_follow(%{assigns: %{user: nil}} = conn, _) do + Logger.debug("Insufficient permissions: follow | write:follows.") + render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."}) + end + defp handle_follow_error(conn, {:auth, _, followee} = _) do render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee}) end -- cgit v1.2.3 From fa7d8e77e64abbbd488152d8063fe9d012c8ac06 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 3 Jan 2020 16:21:52 +0300 Subject: fixed Metadata.Utils.scrub_html_and_truncate --- lib/pleroma/web/metadata/utils.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index 382ecf426..589d11901 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -15,6 +15,7 @@ defmodule Pleroma.Web.Metadata.Utils do |> String.replace(~r//, " ") |> HTML.get_cached_stripped_html_for_activity(object, "metadata") |> Emoji.Formatter.demojify() + |> HtmlEntities.decode() |> Formatter.truncate() end @@ -25,6 +26,7 @@ defmodule Pleroma.Web.Metadata.Utils do |> String.replace(~r//, " ") |> HTML.strip_tags() |> Emoji.Formatter.demojify() + |> HtmlEntities.decode() |> Formatter.truncate(max_length) end -- cgit v1.2.3 From 0b6d1292d29e1f376566fe75aca60c612e9233dc Mon Sep 17 00:00:00 2001 From: eugenijm Date: Fri, 20 Dec 2019 16:38:21 +0300 Subject: Fix mark-as-read (`POST /api/v1/conversations/:id/read`) refreshing updated_at and bringing conversation to the top in the user's direct conversation list --- lib/pleroma/conversation/participation.ex | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index aafe57280..e5d28ebff 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -64,11 +64,13 @@ defmodule Pleroma.Conversation.Participation do end def mark_as_read(participation) do - participation - |> read_cng(%{read: true}) - |> Repo.update() + __MODULE__ + |> where(id: ^participation.id) + |> update(set: [read: true]) + |> select([p], p) + |> Repo.update_all([]) |> case do - {:ok, participation} -> + {1, [participation]} -> participation = Repo.preload(participation, :user) User.set_unread_conversation_count(participation.user) {:ok, participation} -- cgit v1.2.3 From 70410dfafd272bd1f38602446cc4f6e83645326f Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 8 Jan 2020 16:40:38 +0300 Subject: fix create service actor --- lib/pleroma/user.ex | 53 ++++++++++++++++++++++++++--------- lib/pleroma/web/activity_pub/relay.ex | 4 ++- 2 files changed, 43 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 706aee2ff..7ce9e17df 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1430,20 +1430,47 @@ defmodule Pleroma.User do Creates an internal service actor by URI if missing. Optionally takes nickname for addressing. """ - def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do - with user when is_nil(user) <- get_cached_by_ap_id(uri) do - {:ok, user} = - %User{ - invisible: true, - local: true, - ap_id: uri, - nickname: nickname, - follower_address: uri <> "/followers" - } - |> Repo.insert() + @spec get_or_create_service_actor_by_ap_id(String.t(), String.t()) :: User.t() | nil + def get_or_create_service_actor_by_ap_id(uri, nickname) do + {_, user} = + case get_cached_by_ap_id(uri) do + nil -> + with {:error, %{errors: errors}} <- create_service_actor(uri, nickname) do + Logger.error("Cannot create service actor: #{uri}/.\n#{inspect(errors)}") + {:error, nil} + end - user - end + %User{invisible: false} = user -> + set_invisible(user) + + user -> + {:ok, user} + end + + user + end + + @spec set_invisible(User.t()) :: {:ok, User.t()} + defp set_invisible(user) do + user + |> change(%{invisible: true}) + |> update_and_set_cache() + end + + @spec create_service_actor(String.t(), String.t()) :: + {:ok, User.t()} | {:error, Ecto.Changeset.t()} + defp create_service_actor(uri, nickname) do + %User{ + invisible: true, + local: true, + ap_id: uri, + nickname: nickname, + follower_address: uri <> "/followers" + } + |> change + |> unique_constraint(:nickname) + |> Repo.insert() + |> set_cache() end # AP style diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 99a804568..48a1b71e0 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -9,10 +9,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do alias Pleroma.Web.ActivityPub.ActivityPub require Logger + @relay_nickname "relay" + def get_actor do actor = relay_ap_id() - |> User.get_or_create_service_actor_by_ap_id() + |> User.get_or_create_service_actor_by_ap_id(@relay_nickname) actor end -- cgit v1.2.3 From 6c94b7498b889ffe13691123c94bbe5440786852 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 10 Jan 2020 10:52:21 +0300 Subject: [#1478] OAuth admin tweaks: enforced OAuth admin scopes usage by default, migrated existing OAuth records. Adjusted tests. --- lib/pleroma/plugs/user_is_admin_plug.ex | 1 + lib/pleroma/user.ex | 23 +++++++---------------- lib/pleroma/web/oauth/oauth_controller.ex | 10 +++++----- lib/pleroma/web/oauth/scopes.ex | 24 +++--------------------- 4 files changed, 16 insertions(+), 42 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index 582fb1f92..3190163d3 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do token && OAuth.Scopes.contains_admin_scopes?(token.scopes) -> # Note: checking for _any_ admin scope presence, not necessarily fitting requested action. # Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements. + # Admin might opt out of admin scope for some apps to block any admin actions from them. conn true -> diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 706aee2ff..40cc93e03 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1847,22 +1847,13 @@ defmodule Pleroma.User do end def admin_api_update(user, params) do - changeset = - cast(user, params, [ - :is_moderator, - :is_admin, - :show_role - ]) - - with {:ok, updated_user} <- update_and_set_cache(changeset) do - if user.is_admin && !updated_user.is_admin do - # Tokens & authorizations containing any admin scopes must be revoked (revoking all). - # This is an extra safety measure (tokens' admin scopes won't be accepted for non-admins). - global_sign_out(user) - end - - {:ok, updated_user} - end + user + |> cast(params, [ + :is_moderator, + :is_admin, + :show_role + ]) + |> update_and_set_cache() end @doc "Signs user out of all applications" diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 87acdec97..d31a3d91c 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -222,7 +222,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do {:user_active, true} <- {:user_active, !user.deactivated}, {:password_reset_pending, false} <- {:password_reset_pending, user.password_reset_pending}, - {:ok, scopes} <- validate_scopes(app, params, user), + {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do json(conn, Token.Response.build(user, token)) @@ -471,7 +471,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)}, %App{} = app <- Repo.get_by(App, client_id: client_id), true <- redirect_uri in String.split(app.redirect_uris), - {:ok, scopes} <- validate_scopes(app, auth_attrs, user), + {:ok, scopes} <- validate_scopes(app, auth_attrs), {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do Authorization.create_authorization(app, user, scopes) end @@ -487,12 +487,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp put_session_registration_id(%Plug.Conn{} = conn, registration_id), do: put_session(conn, :registration_id, registration_id) - @spec validate_scopes(App.t(), map(), User.t()) :: + @spec validate_scopes(App.t(), map()) :: {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} - defp validate_scopes(%App{} = app, params, %User{} = user) do + defp validate_scopes(%App{} = app, params) do params |> Scopes.fetch_scopes(app.scopes) - |> Scopes.validate(app.scopes, user) + |> Scopes.validate(app.scopes) end def default_redirect_uri(%App{} = app) do diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex index 00da225b9..151467494 100644 --- a/lib/pleroma/web/oauth/scopes.ex +++ b/lib/pleroma/web/oauth/scopes.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.OAuth.Scopes do """ alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.User @doc """ Fetch scopes from request params. @@ -56,35 +55,18 @@ defmodule Pleroma.Web.OAuth.Scopes do @doc """ Validates scopes. """ - @spec validate(list() | nil, list(), User.t()) :: + @spec validate(list() | nil, list()) :: {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} - def validate(blank_scopes, _app_scopes, _user) when blank_scopes in [nil, []], + def validate(blank_scopes, _app_scopes) when blank_scopes in [nil, []], do: {:error, :missing_scopes} - def validate(scopes, app_scopes, %User{} = user) do - with {:ok, _} <- ensure_scopes_support(scopes, app_scopes), - {:ok, scopes} <- authorize_admin_scopes(scopes, app_scopes, user) do - {:ok, scopes} - end - end - - defp ensure_scopes_support(scopes, app_scopes) do + def validate(scopes, app_scopes) do case OAuthScopesPlug.filter_descendants(scopes, app_scopes) do ^scopes -> {:ok, scopes} _ -> {:error, :unsupported_scopes} end end - defp authorize_admin_scopes(scopes, app_scopes, %User{} = user) do - if user.is_admin || !contains_admin_scopes?(scopes) || !contains_admin_scopes?(app_scopes) do - {:ok, scopes} - else - # Gracefully dropping admin scopes from requested scopes if user isn't an admin (not raising) - scopes = scopes -- OAuthScopesPlug.filter_descendants(scopes, ["admin"]) - validate(scopes, app_scopes, user) - end - end - def contains_admin_scopes?(scopes) do scopes |> OAuthScopesPlug.filter_descendants(["admin"]) -- cgit v1.2.3 From 2753285b7722fdb47f0ebb2180e997cf72f65d1a Mon Sep 17 00:00:00 2001 From: Alex S Date: Sun, 29 Sep 2019 11:17:38 +0300 Subject: config editing through database --- lib/mix/tasks/pleroma/config.ex | 107 +++++++++++------- lib/pleroma/config/transfer_task.ex | 59 +++++----- lib/pleroma/docs/generator.ex | 120 +++++++++++++------- lib/pleroma/docs/json.ex | 20 ++-- .../activity_pub/mrf/media_proxy_warming_policy.ex | 60 ++++++++++ .../activity_pub/mrf/mediaproxy_warming_policy.ex | 60 ---------- lib/pleroma/web/activity_pub/mrf/no_op_policy.ex | 16 +++ lib/pleroma/web/activity_pub/mrf/noop_policy.ex | 16 --- .../web/activity_pub/mrf/user_allow_list_policy.ex | 44 ++++++++ .../web/activity_pub/mrf/user_allowlist_policy.ex | 44 -------- .../web/activity_pub/mrf/vocabulary_policy.ex | 3 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 44 ++++++-- lib/pleroma/web/admin_api/config.ex | 122 ++++++++++++++------- lib/pleroma/web/router.ex | 1 + 14 files changed, 427 insertions(+), 289 deletions(-) create mode 100644 lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex delete mode 100644 lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex create mode 100644 lib/pleroma/web/activity_pub/mrf/no_op_policy.ex delete mode 100644 lib/pleroma/web/activity_pub/mrf/noop_policy.ex create mode 100644 lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex delete mode 100644 lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 590c7a914..bb126463c 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -9,27 +9,29 @@ defmodule Mix.Tasks.Pleroma.Config do alias Pleroma.Web.AdminAPI.Config @shortdoc "Manages the location of the config" @moduledoc File.read!("docs/administration/CLI_tasks/config.md") + + @groups [ + :pleroma, + :logger, + :quack, + :mime, + :tesla, + :phoenix, + :cors_plug, + :auto_linker, + :esshd, + :ueberauth, + :prometheus, + :http_signatures, + :web_push_encryption, + :joken + ] + def run(["migrate_to_db"]) do start_pleroma() if Pleroma.Config.get([:instance, :dynamic_configuration]) do - Application.get_all_env(:pleroma) - |> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end) - |> Enum.each(fn {k, v} -> - key = to_string(k) |> String.replace("Elixir.", "") - - key = - if String.starts_with?(key, "Pleroma.") do - key - else - ":" <> key - end - - {:ok, _} = Config.update_or_create(%{group: "pleroma", key: key, value: v}) - Mix.shell().info("#{key} is migrated.") - end) - - Mix.shell().info("Settings migrated.") + Enum.each(@groups, &load_and_create(&1)) else Mix.shell().info( "Migration is not allowed by config. You can change this behavior in instance settings." @@ -37,38 +39,63 @@ defmodule Mix.Tasks.Pleroma.Config do end end - def run(["migrate_from_db", env, delete?]) do + def run(["migrate_from_db" | options]) do start_pleroma() - delete? = if delete? == "true", do: true, else: false - - if Pleroma.Config.get([:instance, :dynamic_configuration]) do - config_path = "config/#{env}.exported_from_db.secret.exs" + {opts, _} = + OptionParser.parse!(options, + strict: [env: :string, delete_from_db: :boolean], + aliases: [d: :delete_from_db] + ) - {:ok, file} = File.open(config_path, [:write, :utf8]) + with {:active?, true} <- {:active?, Pleroma.Config.get([:instance, :dynamic_configuration])}, + env_path when is_binary(env_path) <- opts[:env], + config_path <- "config/#{env_path}.exported_from_db.secret.exs", + {:ok, file} <- File.open(config_path, [:write, :utf8]) do IO.write(file, "use Mix.Config\r\n") - Repo.all(Config) - |> Enum.each(fn config -> - IO.write( - file, - "config :#{config.group}, #{config.key}, #{ - inspect(Config.from_binary(config.value), limit: :infinity) - }\r\n\r\n" - ) - - if delete? do - {:ok, _} = Repo.delete(config) - Mix.shell().info("#{config.key} deleted from DB.") - end - end) + Config + |> Repo.all() + |> Enum.each(&write_to_file_with_deletion(&1, file, opts[:delete_from_db])) File.close(file) System.cmd("mix", ["format", config_path]) else - Mix.shell().info( - "Migration is not allowed by config. You can change this behavior in instance settings." - ) + {:active?, false} -> + Mix.shell().info( + "migration is not allowed by config. You can change this behavior in instance settings." + ) + + error -> + Mix.shell().info("error occuried while opening file. #{inspect(error)}") + end + end + + defp load_and_create(group) do + group + |> Application.get_all_env() + |> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end) + |> Enum.each(fn {key, value} -> + key_str = inspect(key) + + {:ok, _} = Config.update_or_create(%{group: ":#{group}", key: key_str, value: value}) + Mix.shell().info("settings for key #{key_str} migrated.") + end) + + Mix.shell().info("settings for group :#{group} migrated.") + end + + defp write_to_file_with_deletion(config, file, with_deletion) do + IO.write( + file, + "config #{config.group}, #{config.key}, #{ + inspect(Config.from_binary(config.value), limit: :infinity) + }\r\n\r\n" + ) + + if with_deletion do + {:ok, _} = Repo.delete(config) + Mix.shell().info("#{config.key} deleted from DB.") end end end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 3214c9951..0bc4c4029 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -4,56 +4,59 @@ defmodule Pleroma.Config.TransferTask do use Task + + require Logger + + alias Pleroma.Repo alias Pleroma.Web.AdminAPI.Config def start_link(_) do load_and_update_env() - if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Pleroma.Repo) + if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo) :ignore end def load_and_update_env do - if Pleroma.Config.get([:instance, :dynamic_configuration]) and - Ecto.Adapters.SQL.table_exists?(Pleroma.Repo, "config") do - for_restart = - Pleroma.Repo.all(Config) - |> Enum.map(&update_env(&1)) - + with true <- Pleroma.Config.get([:instance, :dynamic_configuration]), + true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"), + started_applications <- Application.started_applications() do # We need to restart applications for loaded settings take effect - for_restart - |> Enum.reject(&(&1 in [:pleroma, :ok])) - |> Enum.each(fn app -> - Application.stop(app) - :ok = Application.start(app) - end) + Config + |> Repo.all() + |> Enum.map(&update_env(&1)) + |> Enum.uniq() + # TODO: some problem with prometheus after restart! + |> Enum.reject(&(&1 in [:pleroma, nil, :prometheus])) + |> Enum.each(&restart(started_applications, &1)) end end defp update_env(setting) do try do - key = - if String.starts_with?(setting.key, "Pleroma.") do - "Elixir." <> setting.key - else - String.trim_leading(setting.key, ":") - end + key = Config.from_string(setting.key) + group = Config.from_string(setting.group) + value = Config.from_binary(setting.value) - group = String.to_existing_atom(setting.group) - - Application.put_env( - group, - String.to_existing_atom(key), - Config.from_binary(setting.value) - ) + :ok = Application.put_env(group, key, value) group rescue e -> - require Logger - Logger.warn( "updating env causes error, key: #{inspect(setting.key)}, error: #{inspect(e)}" ) + + nil + end + end + + defp restart(started_applications, app) do + with {^app, _, _} <- List.keyfind(started_applications, app, 0), + :ok <- Application.stop(app) do + :ok = Application.start(app) + else + nil -> Logger.warn("#{app} is not started.") + error -> Logger.warn(inspect(error)) end end end diff --git a/lib/pleroma/docs/generator.ex b/lib/pleroma/docs/generator.ex index aa578eee2..b57e47e8b 100644 --- a/lib/pleroma/docs/generator.ex +++ b/lib/pleroma/docs/generator.ex @@ -6,68 +6,108 @@ defmodule Pleroma.Docs.Generator do implementation.process(descriptions) end - @spec uploaders_list() :: [module()] - def uploaders_list do - {:ok, modules} = :application.get_key(:pleroma, :modules) + @spec list_modules_in_dir(String.t(), String.t()) :: [module()] + def list_modules_in_dir(dir, start) do + with {:ok, files} <- File.ls(dir) do + files + |> Enum.filter(&String.ends_with?(&1, ".ex")) + |> Enum.map(fn filename -> + module = filename |> String.trim_trailing(".ex") |> Macro.camelize() + String.to_existing_atom(start <> module) + end) + end + end + + @doc """ + Converts: + - atoms to strings with leading `:` + - module names to strings, without leading `Elixir.` + - add humanized labels to `keys` if label is not defined, e.g. `:instance` -> `Instance` + """ + @spec convert_to_strings([map()]) :: [map()] + def convert_to_strings(descriptions) do + Enum.map(descriptions, &format_entity(&1)) + end + + defp format_entity(entity) do + entity + |> format_key() + |> Map.put(:group, atom_to_string(entity[:group])) + |> format_children() + end - Enum.filter(modules, fn module -> - name_as_list = Module.split(module) + defp format_key(%{key: key} = entity) do + entity + |> Map.put(:key, atom_to_string(key)) + |> Map.put(:label, entity[:label] || humanize(key)) + end - List.starts_with?(name_as_list, ["Pleroma", "Uploaders"]) and - List.last(name_as_list) != "Uploader" - end) + defp format_key(%{group: group} = entity) do + Map.put(entity, :label, entity[:label] || humanize(group)) end - @spec filters_list() :: [module()] - def filters_list do - {:ok, modules} = :application.get_key(:pleroma, :modules) + defp format_key(entity), do: entity + + defp format_children(%{children: children} = entity) do + Map.put(entity, :children, Enum.map(children, &format_child(&1))) + end - Enum.filter(modules, fn module -> - name_as_list = Module.split(module) + defp format_children(entity), do: entity + + defp format_child(%{suggestions: suggestions} = entity) do + entity + |> Map.put(:suggestions, format_suggestions(suggestions)) + |> format_key() + |> format_children() + end - List.starts_with?(name_as_list, ["Pleroma", "Upload", "Filter"]) - end) + defp format_child(entity) do + entity + |> format_key() + |> format_children() end - @spec mrf_list() :: [module()] - def mrf_list do - {:ok, modules} = :application.get_key(:pleroma, :modules) + defp atom_to_string(entity) when is_binary(entity), do: entity - Enum.filter(modules, fn module -> - name_as_list = Module.split(module) + defp atom_to_string(entity) when is_atom(entity), do: inspect(entity) - List.starts_with?(name_as_list, ["Pleroma", "Web", "ActivityPub", "MRF"]) and - length(name_as_list) > 4 - end) + defp humanize(entity) do + string = inspect(entity) + + if String.starts_with?(string, ":"), + do: Phoenix.Naming.humanize(entity), + else: string end - @spec richmedia_parsers() :: [module()] - def richmedia_parsers do - {:ok, modules} = :application.get_key(:pleroma, :modules) + defp format_suggestions([]), do: [] + + defp format_suggestions([suggestion | tail]) do + [format_suggestion(suggestion) | format_suggestions(tail)] + end + + defp format_suggestion(entity) when is_atom(entity) do + atom_to_string(entity) + end - Enum.filter(modules, fn module -> - name_as_list = Module.split(module) + defp format_suggestion([head | tail] = entity) when is_list(entity) do + [format_suggestion(head) | format_suggestions(tail)] + end - List.starts_with?(name_as_list, ["Pleroma", "Web", "RichMedia", "Parsers"]) and - length(name_as_list) == 5 - end) + defp format_suggestion(entity) when is_tuple(entity) do + format_suggestions(Tuple.to_list(entity)) |> List.to_tuple() end + + defp format_suggestion(entity), do: entity end defimpl Jason.Encoder, for: Tuple do - def encode(tuple, opts) do - Jason.Encode.list(Tuple.to_list(tuple), opts) - end + def encode(tuple, opts), do: Jason.Encode.list(Tuple.to_list(tuple), opts) end defimpl Jason.Encoder, for: [Regex, Function] do - def encode(term, opts) do - Jason.Encode.string(inspect(term), opts) - end + def encode(term, opts), do: Jason.Encode.string(inspect(term), opts) end defimpl String.Chars, for: Regex do - def to_string(term) do - inspect(term) - end + def to_string(term), do: inspect(term) end diff --git a/lib/pleroma/docs/json.ex b/lib/pleroma/docs/json.ex index f2a56d845..f191b6013 100644 --- a/lib/pleroma/docs/json.ex +++ b/lib/pleroma/docs/json.ex @@ -3,18 +3,22 @@ defmodule Pleroma.Docs.JSON do @spec process(keyword()) :: {:ok, String.t()} def process(descriptions) do - config_path = "docs/generate_config.json" - - with {:ok, file} <- File.open(config_path, [:write, :utf8]), - json <- generate_json(descriptions), + with path <- "docs/generated_config.json", + {:ok, file} <- File.open(path, [:write, :utf8]), + formatted_descriptions <- + Pleroma.Docs.Generator.convert_to_strings(descriptions), + json <- Jason.encode!(formatted_descriptions), :ok <- IO.write(file, json), :ok <- File.close(file) do - {:ok, config_path} + {:ok, path} end end - @spec generate_json([keyword()]) :: String.t() - def generate_json(descriptions) do - Jason.encode!(descriptions) + def compile do + with {config, _paths} <- Mix.Config.eval!("config/description.exs") do + config[:pleroma][:config_description] + |> Pleroma.Docs.Generator.convert_to_strings() + |> Jason.encode!() + end end end diff --git a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex new file mode 100644 index 000000000..df774b0f7 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do + @moduledoc "Preloads any attachments in the MediaProxy cache by prefetching them" + @behaviour Pleroma.Web.ActivityPub.MRF + + alias Pleroma.HTTP + alias Pleroma.Web.MediaProxy + alias Pleroma.Workers.BackgroundWorker + + require Logger + + @hackney_options [ + pool: :media, + recv_timeout: 10_000 + ] + + def perform(:prefetch, url) do + Logger.debug("Prefetching #{inspect(url)}") + + url + |> MediaProxy.url() + |> HTTP.get([], adapter: @hackney_options) + end + + def perform(:preload, %{"object" => %{"attachment" => attachments}} = _message) do + Enum.each(attachments, fn + %{"url" => url} when is_list(url) -> + url + |> Enum.each(fn + %{"href" => href} -> + BackgroundWorker.enqueue("media_proxy_prefetch", %{"url" => href}) + + x -> + Logger.debug("Unhandled attachment URL object #{inspect(x)}") + end) + + x -> + Logger.debug("Unhandled attachment #{inspect(x)}") + end) + end + + @impl true + def filter( + %{"type" => "Create", "object" => %{"attachment" => attachments} = _object} = message + ) + when is_list(attachments) and length(attachments) > 0 do + BackgroundWorker.enqueue("media_proxy_preload", %{"message" => message}) + + {:ok, message} + end + + @impl true + def filter(message), do: {:ok, message} + + @impl true + def describe, do: {:ok, %{}} +end diff --git a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex deleted file mode 100644 index df774b0f7..000000000 --- a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex +++ /dev/null @@ -1,60 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do - @moduledoc "Preloads any attachments in the MediaProxy cache by prefetching them" - @behaviour Pleroma.Web.ActivityPub.MRF - - alias Pleroma.HTTP - alias Pleroma.Web.MediaProxy - alias Pleroma.Workers.BackgroundWorker - - require Logger - - @hackney_options [ - pool: :media, - recv_timeout: 10_000 - ] - - def perform(:prefetch, url) do - Logger.debug("Prefetching #{inspect(url)}") - - url - |> MediaProxy.url() - |> HTTP.get([], adapter: @hackney_options) - end - - def perform(:preload, %{"object" => %{"attachment" => attachments}} = _message) do - Enum.each(attachments, fn - %{"url" => url} when is_list(url) -> - url - |> Enum.each(fn - %{"href" => href} -> - BackgroundWorker.enqueue("media_proxy_prefetch", %{"url" => href}) - - x -> - Logger.debug("Unhandled attachment URL object #{inspect(x)}") - end) - - x -> - Logger.debug("Unhandled attachment #{inspect(x)}") - end) - end - - @impl true - def filter( - %{"type" => "Create", "object" => %{"attachment" => attachments} = _object} = message - ) - when is_list(attachments) and length(attachments) > 0 do - BackgroundWorker.enqueue("media_proxy_preload", %{"message" => message}) - - {:ok, message} - end - - @impl true - def filter(message), do: {:ok, message} - - @impl true - def describe, do: {:ok, %{}} -end diff --git a/lib/pleroma/web/activity_pub/mrf/no_op_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_op_policy.ex new file mode 100644 index 000000000..878c57925 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/no_op_policy.ex @@ -0,0 +1,16 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do + @moduledoc "Does nothing (lets the messages go through unmodified)" + @behaviour Pleroma.Web.ActivityPub.MRF + + @impl true + def filter(object) do + {:ok, object} + end + + @impl true + def describe, do: {:ok, %{}} +end diff --git a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex deleted file mode 100644 index 878c57925..000000000 --- a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex +++ /dev/null @@ -1,16 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do - @moduledoc "Does nothing (lets the messages go through unmodified)" - @behaviour Pleroma.Web.ActivityPub.MRF - - @impl true - def filter(object) do - {:ok, object} - end - - @impl true - def describe, do: {:ok, %{}} -end diff --git a/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex b/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex new file mode 100644 index 000000000..7389d6a96 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do + alias Pleroma.Config + + @moduledoc "Accept-list of users from specified instances" + @behaviour Pleroma.Web.ActivityPub.MRF + + defp filter_by_list(object, []), do: {:ok, object} + + defp filter_by_list(%{"actor" => actor} = object, allow_list) do + if actor in allow_list do + {:ok, object} + else + {:reject, nil} + end + end + + @impl true + def filter(%{"actor" => actor} = object) do + actor_info = URI.parse(actor) + + allow_list = + Config.get( + [:mrf_user_allowlist, String.to_atom(actor_info.host)], + [] + ) + + filter_by_list(object, allow_list) + end + + def filter(object), do: {:ok, object} + + @impl true + def describe do + mrf_user_allowlist = + Config.get([:mrf_user_allowlist], []) + |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) + + {:ok, %{mrf_user_allowlist: mrf_user_allowlist}} + end +end diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex deleted file mode 100644 index 7389d6a96..000000000 --- a/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex +++ /dev/null @@ -1,44 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do - alias Pleroma.Config - - @moduledoc "Accept-list of users from specified instances" - @behaviour Pleroma.Web.ActivityPub.MRF - - defp filter_by_list(object, []), do: {:ok, object} - - defp filter_by_list(%{"actor" => actor} = object, allow_list) do - if actor in allow_list do - {:ok, object} - else - {:reject, nil} - end - end - - @impl true - def filter(%{"actor" => actor} = object) do - actor_info = URI.parse(actor) - - allow_list = - Config.get( - [:mrf_user_allowlist, String.to_atom(actor_info.host)], - [] - ) - - filter_by_list(object, allow_list) - end - - def filter(object), do: {:ok, object} - - @impl true - def describe do - mrf_user_allowlist = - Config.get([:mrf_user_allowlist], []) - |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) - - {:ok, %{mrf_user_allowlist: mrf_user_allowlist}} - end -end diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex index 4eaea00d8..9a03d67c0 100644 --- a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -19,8 +19,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do def filter(%{"type" => message_type} = message) do with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]), rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]), - true <- - length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type), + true <- accepted_vocabulary == [] || Enum.member?(accepted_vocabulary, message_type), false <- length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type), {:ok, _} <- filter(message["object"]) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index c8abeff06..376f88061 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -4,6 +4,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [json_response: 3] + alias Pleroma.Activity alias Pleroma.ModerationLog alias Pleroma.Plugs.OAuthScopesPlug @@ -25,10 +28,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.Router - import Pleroma.Web.ControllerHelper, only: [json_response: 3] - require Logger + @descriptions_json Pleroma.Docs.JSON.compile() + @users_page_size 50 + plug( OAuthScopesPlug, %{scopes: ["read:accounts"], admin: true} @@ -93,8 +97,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do when action in [:relay_follow, :relay_unfollow, :config_update] ) - @users_page_size 50 - action_fallback(:errors) def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do @@ -782,10 +784,22 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def migrate_from_db(conn, _params) do - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "true"]) + Mix.Tasks.Pleroma.Config.run([ + "migrate_from_db", + "--env", + to_string(Pleroma.Config.get(:env)), + "-d" + ]) + json(conn, %{}) end + def config_descriptions(conn, _params) do + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, @descriptions_json) + end + def config_show(conn, _params) do configs = Pleroma.Repo.all(Config) @@ -800,17 +814,27 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do updated = Enum.map(configs, fn %{"group" => group, "key" => key, "delete" => "true"} = params -> - {:ok, config} = Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) - config + with {:ok, config} <- + Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) do + config + end %{"group" => group, "key" => key, "value" => value} -> - {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value}) - config + with {:ok, config} <- + Config.update_or_create(%{group: group, key: key, value: value}) do + config + end end) |> Enum.reject(&is_nil(&1)) Pleroma.Config.TransferTask.load_and_update_env() - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"]) + + Mix.Tasks.Pleroma.Config.run([ + "migrate_from_db", + "--env", + to_string(Pleroma.Config.get(:env)) + ]) + updated else [] diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index 1917a5580..a74acfbc6 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -24,6 +24,8 @@ defmodule Pleroma.Web.AdminAPI.Config do @spec changeset(Config.t(), map()) :: Changeset.t() def changeset(config, params \\ %{}) do + params = Map.put(params, :value, transform(params[:value])) + config |> cast(params, [:key, :group, :value]) |> validate_required([:key, :group, :value]) @@ -33,42 +35,43 @@ defmodule Pleroma.Web.AdminAPI.Config do @spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} def create(params) do %Config{} - |> changeset(Map.put(params, :value, transform(params[:value]))) + |> changeset(params) |> Repo.insert() end @spec update(Config.t(), map()) :: {:ok, Config} | {:error, Changeset.t()} def update(%Config{} = config, %{value: value}) do config - |> change(value: transform(value)) + |> changeset(%{value: value}) |> Repo.update() end @spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} def update_or_create(params) do - with %Config{} = config <- Config.get_by_params(Map.take(params, [:group, :key])) do + search_opts = Map.take(params, [:group, :key]) + + with %Config{} = config <- Config.get_by_params(search_opts) do Config.update(config, params) else nil -> Config.create(params) end end - @spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} + @spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} | {:ok, nil} def delete(params) do - with %Config{} = config <- Config.get_by_params(Map.delete(params, :subkeys)) do - if params[:subkeys] do - updated_value = - Keyword.drop( - :erlang.binary_to_term(config.value), - Enum.map(params[:subkeys], &do_transform_string(&1)) - ) - - Config.update(config, %{value: updated_value}) - else + search_opts = Map.delete(params, :subkeys) + + with %Config{} = config <- Config.get_by_params(search_opts), + {config, sub_keys} when is_list(sub_keys) <- {config, params[:subkeys]}, + old_value <- :erlang.binary_to_term(config.value), + keys <- Enum.map(sub_keys, &do_transform_string(&1)), + new_value <- Keyword.drop(old_value, keys) do + Config.update(config, %{value: new_value}) + else + {config, nil} -> Repo.delete(config) {:ok, nil} - end - else + nil -> err = dgettext("errors", "Config with params %{params} not found", params: inspect(params)) @@ -82,10 +85,22 @@ defmodule Pleroma.Web.AdminAPI.Config do @spec from_binary_with_convert(binary()) :: any() def from_binary_with_convert(binary) do - from_binary(binary) + binary + |> from_binary() |> do_convert() end + @spec from_string(String.t()) :: atom() | no_return() + def from_string(":" <> entity), do: String.to_existing_atom(entity) + + def from_string(entity) when is_binary(entity) do + if is_module_name?(entity) do + String.to_existing_atom("Elixir.#{entity}") + else + entity + end + end + defp do_convert(entity) when is_list(entity) do for v <- entity, into: [], do: do_convert(v) end @@ -97,6 +112,7 @@ defmodule Pleroma.Web.AdminAPI.Config do end defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]} + # TODO: will become useless after removing hackney defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]} defp do_convert(entity) when is_tuple(entity), @@ -105,21 +121,15 @@ defmodule Pleroma.Web.AdminAPI.Config do defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity), do: entity - defp do_convert(entity) when is_atom(entity) do - string = to_string(entity) - - if String.starts_with?(string, "Elixir."), - do: do_convert(string), - else: ":" <> string - end - - defp do_convert("Elixir." <> module_name), do: module_name + defp do_convert(entity) when is_atom(entity), do: inspect(entity) defp do_convert(entity) when is_binary(entity), do: entity - @spec transform(any()) :: binary() + @spec transform(any()) :: binary() | no_return() def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do - :erlang.term_to_binary(do_transform(entity)) + entity + |> do_transform() + |> :erlang.term_to_binary() end def transform(entity), do: :erlang.term_to_binary(entity) @@ -131,6 +141,7 @@ defmodule Pleroma.Web.AdminAPI.Config do {:dispatch, [dispatch_settings]} end + # TODO: will become useless after removing hackney defp do_transform(%{"tuple" => [":partial_chain", entity]}) do {partial_chain, []} = do_eval(entity) {:partial_chain, partial_chain} @@ -149,34 +160,63 @@ defmodule Pleroma.Web.AdminAPI.Config do end defp do_transform(entity) when is_binary(entity) do - String.trim(entity) + entity + |> String.trim() |> do_transform_string() end defp do_transform(entity), do: entity - defp do_transform_string("~r/" <> pattern) do - modificator = String.split(pattern, "/") |> List.last() - pattern = String.trim_trailing(pattern, "/" <> modificator) + @delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}] + + defp find_valid_delimiter([], _string, _), + do: raise(ArgumentError, message: "valid delimiter for Regex expression not found") - case modificator do - "" -> ~r/#{pattern}/ - "i" -> ~r/#{pattern}/i - "u" -> ~r/#{pattern}/u - "s" -> ~r/#{pattern}/s + defp find_valid_delimiter([{leading, closing} = delimiter | others], pattern, regex_delimiter) + when is_tuple(delimiter) do + if String.contains?(pattern, closing) do + find_valid_delimiter(others, pattern, regex_delimiter) + else + {:ok, {leading, closing}} + end + end + + defp find_valid_delimiter([delimiter | others], pattern, regex_delimiter) do + if String.contains?(pattern, delimiter) do + find_valid_delimiter(others, pattern, regex_delimiter) + else + {:ok, {delimiter, delimiter}} + end + end + + @regex_parts ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u + + defp do_transform_string("~r" <> _pattern = regex) do + with %{"modifier" => modifier, "pattern" => pattern, "delimiter" => regex_delimiter} <- + Regex.named_captures(@regex_parts, regex), + {:ok, {leading, closing}} <- find_valid_delimiter(@delimiters, pattern, regex_delimiter), + {result, _} <- Code.eval_string("~r#{leading}#{pattern}#{closing}#{modifier}") do + result end end defp do_transform_string(":" <> atom), do: String.to_atom(atom) defp do_transform_string(value) do - if String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix"), - do: String.to_existing_atom("Elixir." <> value), - else: value + if is_module_name?(value) do + String.to_existing_atom("Elixir." <> value) + else + value + end + end + + @spec is_module_name?(String.t()) :: boolean() + def is_module_name?(string) do + Regex.match?(~r/^(Pleroma|Phoenix|Tesla)\./, string) or string in ["Oban", "Ueberauth"] end defp do_eval(entity) do cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "") - Code.eval_string(cleaned_string, [], requires: [], macros: []) + Code.eval_string(cleaned_string) end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f6c128283..a182e90e7 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -195,6 +195,7 @@ defmodule Pleroma.Web.Router do get("/config", AdminAPIController, :config_show) post("/config", AdminAPIController, :config_update) + get("/config/descriptions", AdminAPIController, :config_descriptions) get("/config/migrate_to_db", AdminAPIController, :migrate_to_db) get("/config/migrate_from_db", AdminAPIController, :migrate_from_db) -- cgit v1.2.3 From 0656816c77875d87d64d89e0e549f73104104cfb Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 6 Dec 2019 08:21:30 +0300 Subject: tests for setttings without an explicit key --- lib/mix/tasks/pleroma/config.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index bb126463c..cef02b864 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -76,10 +76,10 @@ defmodule Mix.Tasks.Pleroma.Config do |> Application.get_all_env() |> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end) |> Enum.each(fn {key, value} -> - key_str = inspect(key) + key = inspect(key) + {:ok, _} = Config.update_or_create(%{group: inspect(group), key: key, value: value}) - {:ok, _} = Config.update_or_create(%{group: ":#{group}", key: key_str, value: value}) - Mix.shell().info("settings for key #{key_str} migrated.") + Mix.shell().info("settings for key #{key} migrated.") end) Mix.shell().info("settings for group :#{group} migrated.") -- cgit v1.2.3 From 5cacb988b99347b228a30743fbcf310c9479b3f9 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 6 Dec 2019 15:12:56 +0300 Subject: partially settings update --- lib/pleroma/web/admin_api/config.ex | 49 ++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index a74acfbc6..e141a13da 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -46,14 +46,48 @@ defmodule Pleroma.Web.AdminAPI.Config do |> Repo.update() end + @full_key_update [ + {:pleroma, :ecto_repos}, + {:quack, :meta}, + {:mime, :types}, + {:cors_plug, [:max_age, :methods, :expose, :headers]}, + {:auto_linker, :opts}, + {:swarm, :node_blacklist} + ] + + defp only_full_update?(%Config{} = config) do + config_group = Config.from_string(config.group) + config_key = Config.from_string(config.key) + + Enum.any?(@full_key_update, fn + {group, key} when is_list(key) -> + config_group == group and config_key in key + + {group, key} -> + config_group == group and config_key == key + end) + end + + defp can_be_partially_updated?(%Config{} = config), do: not only_full_update?(config) + @spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} def update_or_create(params) do search_opts = Map.take(params, [:group, :key]) - with %Config{} = config <- Config.get_by_params(search_opts) do - Config.update(config, params) + with %Config{} = config <- Config.get_by_params(search_opts), + {:partial_update, true, config} <- + {:partial_update, can_be_partially_updated?(config), config}, + old_value <- from_binary(config.value), + transformed_value <- do_transform(params[:value]), + {:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config}, + new_value <- Keyword.merge(old_value, transformed_value) do + Config.update(config, %{value: new_value, transformed?: true}) else - nil -> Config.create(params) + {reason, false, config} when reason in [:partial_update, :can_be_merged] -> + Config.update(config, params) + + nil -> + Config.create(params) end end @@ -63,7 +97,7 @@ defmodule Pleroma.Web.AdminAPI.Config do with %Config{} = config <- Config.get_by_params(search_opts), {config, sub_keys} when is_list(sub_keys) <- {config, params[:subkeys]}, - old_value <- :erlang.binary_to_term(config.value), + old_value <- from_binary(config.value), keys <- Enum.map(sub_keys, &do_transform_string(&1)), new_value <- Keyword.drop(old_value, keys) do Config.update(config, %{value: new_value}) @@ -129,10 +163,13 @@ defmodule Pleroma.Web.AdminAPI.Config do def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do entity |> do_transform() - |> :erlang.term_to_binary() + |> to_binary() end - def transform(entity), do: :erlang.term_to_binary(entity) + def transform(entity), do: to_binary(entity) + + @spec to_binary(any()) :: binary() + def to_binary(entity), do: :erlang.term_to_binary(entity) defp do_transform(%Regex{} = entity), do: entity -- cgit v1.2.3 From fea734ca703b686701b87c8c4c4969deb05d1f92 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 6 Dec 2019 17:50:53 +0300 Subject: errors on endpoints --- lib/pleroma/web/admin_api/admin_api_controller.ex | 110 ++++++++++++---------- 1 file changed, 58 insertions(+), 52 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 376f88061..23dcbedba 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -778,71 +778,77 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do |> render("index.json", %{log: log}) end - def migrate_to_db(conn, _params) do - Mix.Tasks.Pleroma.Config.run(["migrate_to_db"]) - json(conn, %{}) - end - - def migrate_from_db(conn, _params) do - Mix.Tasks.Pleroma.Config.run([ - "migrate_from_db", - "--env", - to_string(Pleroma.Config.get(:env)), - "-d" - ]) - - json(conn, %{}) - end - def config_descriptions(conn, _params) do conn |> Plug.Conn.put_resp_content_type("application/json") |> Plug.Conn.send_resp(200, @descriptions_json) end - def config_show(conn, _params) do - configs = Pleroma.Repo.all(Config) + def migrate_from_db(conn, _params) do + with :ok <- check_dynamic_configuration(conn) do + Mix.Tasks.Pleroma.Config.run([ + "migrate_from_db", + "--env", + to_string(Pleroma.Config.get(:env)), + "-d" + ]) - conn - |> put_view(ConfigView) - |> render("index.json", %{configs: configs}) + json(conn, %{}) + end end - def config_update(conn, %{"configs" => configs}) do - updated = - if Pleroma.Config.get([:instance, :dynamic_configuration]) do - updated = - Enum.map(configs, fn - %{"group" => group, "key" => key, "delete" => "true"} = params -> - with {:ok, config} <- - Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) do - config - end - - %{"group" => group, "key" => key, "value" => value} -> - with {:ok, config} <- - Config.update_or_create(%{group: group, key: key, value: value}) do - config - end - end) - |> Enum.reject(&is_nil(&1)) - - Pleroma.Config.TransferTask.load_and_update_env() - - Mix.Tasks.Pleroma.Config.run([ - "migrate_from_db", - "--env", - to_string(Pleroma.Config.get(:env)) - ]) + def config_show(conn, _params) do + with :ok <- check_dynamic_configuration(conn) do + configs = Pleroma.Repo.all(Config) - updated + if configs == [] do + errors(conn, {:error, "To use dynamic configuration migrate your settings to database."}) else - [] + conn + |> put_view(ConfigView) + |> render("index.json", %{configs: configs}) end + end + end - conn - |> put_view(ConfigView) - |> render("index.json", %{configs: updated}) + def config_update(conn, %{"configs" => configs}) do + with :ok <- check_dynamic_configuration(conn) do + updated = + Enum.map(configs, fn + %{"group" => group, "key" => key, "delete" => "true"} = params -> + with {:ok, config} <- + Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) do + config + end + + %{"group" => group, "key" => key, "value" => value} -> + with {:ok, config} <- + Config.update_or_create(%{group: group, key: key, value: value}) do + config + end + end) + |> Enum.reject(&is_nil(&1)) + + Pleroma.Config.TransferTask.load_and_update_env() + + Mix.Tasks.Pleroma.Config.run([ + "migrate_from_db", + "--env", + to_string(Pleroma.Config.get(:env)) + ]) + + conn + |> put_view(ConfigView) + |> render("index.json", %{configs: updated}) + end + end + + defp check_dynamic_configuration(conn) do + if Pleroma.Config.get([:instance, :dynamic_configuration]) do + :ok + else + errors(conn, {:error, "To use this endpoint you need to enable dynamic configuration."}) + end end def reload_emoji(conn, _params) do -- cgit v1.2.3 From a71393dd29488eb86d6da23250b05a9b5b04eb81 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 10 Dec 2019 12:00:40 +0300 Subject: fix for endpoints after env update --- lib/mix/tasks/pleroma/config.ex | 4 +++- lib/pleroma/config/transfer_task.ex | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index cef02b864..257a0dfe5 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -74,7 +74,9 @@ defmodule Mix.Tasks.Pleroma.Config do defp load_and_create(group) do group |> Application.get_all_env() - |> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end) + |> Enum.reject(fn {k, _v} -> + k in [Pleroma.Repo, :env] or (group == :phoenix and k == :serve_endpoints) + end) |> Enum.each(fn {key, value} -> key = inspect(key) {:ok, _} = Config.update_or_create(%{group: inspect(group), key: key, value: value}) diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 0bc4c4029..c89c1fcc8 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -37,7 +37,9 @@ defmodule Pleroma.Config.TransferTask do group = Config.from_string(setting.group) value = Config.from_binary(setting.value) - :ok = Application.put_env(group, key, value) + if group != :phoenix and key != :serve_endpoints do + :ok = Application.put_env(group, key, value) + end group rescue -- cgit v1.2.3 From 583cee46072cda6b3ed07f4ce09b09db9e2b0af1 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 17 Dec 2019 19:51:01 +0300 Subject: parsing proxy url setting --- lib/pleroma/web/admin_api/config.ex | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index e141a13da..acc5a5183 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -145,6 +145,33 @@ defmodule Pleroma.Web.AdminAPI.Config do for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)} end + defp do_convert({:proxy_url, {type, :localhost, port}}) do + %{"tuple" => [":proxy_url", %{"tuple" => [do_convert(type), "localhost", port]}]} + end + + defp do_convert({:proxy_url, {type, host, port}}) when is_tuple(host) do + ip = + host + |> :inet_parse.ntoa() + |> to_string() + + %{ + "tuple" => [ + ":proxy_url", + %{"tuple" => [do_convert(type), ip, port]} + ] + } + end + + defp do_convert({:proxy_url, {type, host, port}}) do + %{ + "tuple" => [ + ":proxy_url", + %{"tuple" => [do_convert(type), to_string(host), port]} + ] + } + end + defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]} # TODO: will become useless after removing hackney defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]} @@ -173,6 +200,10 @@ defmodule Pleroma.Web.AdminAPI.Config do defp do_transform(%Regex{} = entity), do: entity + defp do_transform(%{"tuple" => [":proxy_url", %{"tuple" => [type, host, port]}]}) do + {:proxy_url, {do_transform_string(type), parse_host(host), port}} + end + defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do {dispatch_settings, []} = do_eval(entity) {:dispatch, [dispatch_settings]} @@ -204,6 +235,20 @@ defmodule Pleroma.Web.AdminAPI.Config do defp do_transform(entity), do: entity + defp parse_host("localhost"), do: :localhost + + defp parse_host(host) do + charlist = to_charlist(host) + + case :inet.parse_address(charlist) do + {:error, :einval} -> + charlist + + {:ok, ip} -> + ip + end + end + @delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}] defp find_valid_delimiter([], _string, _), -- cgit v1.2.3 From 063ab6d9115ec17bd1907d42a998f335a0cd69c9 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 19 Dec 2019 10:19:56 +0300 Subject: logger backends fix --- lib/pleroma/web/admin_api/config.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index acc5a5183..a8a698c89 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -52,7 +52,8 @@ defmodule Pleroma.Web.AdminAPI.Config do {:mime, :types}, {:cors_plug, [:max_age, :methods, :expose, :headers]}, {:auto_linker, :opts}, - {:swarm, :node_blacklist} + {:swarm, :node_blacklist}, + {:logger, :backends} ] defp only_full_update?(%Config{} = config) do -- cgit v1.2.3 From cda2c1fc630e455b3d419f5c3b22c366dc883ce1 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 20 Dec 2019 10:22:53 +0300 Subject: fix for subgroup tuple added settings for swoosh adapters local --- lib/pleroma/docs/generator.ex | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/docs/generator.ex b/lib/pleroma/docs/generator.ex index b57e47e8b..6b12dcdd9 100644 --- a/lib/pleroma/docs/generator.ex +++ b/lib/pleroma/docs/generator.ex @@ -58,15 +58,23 @@ defmodule Pleroma.Docs.Generator do entity |> Map.put(:suggestions, format_suggestions(suggestions)) |> format_key() + |> format_group() |> format_children() end defp format_child(entity) do entity |> format_key() + |> format_group() |> format_children() end + defp format_group(%{group: group} = entity) do + Map.put(entity, :group, format_suggestion(group)) + end + + defp format_group(entity), do: entity + defp atom_to_string(entity) when is_binary(entity), do: entity defp atom_to_string(entity) when is_atom(entity), do: inspect(entity) -- cgit v1.2.3 From 9c1f3bfeffa7e40d319d931c975b948f33800c40 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 21 Dec 2019 13:54:22 +0300 Subject: fixes for logger backends --- lib/pleroma/web/admin_api/config.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index a8a698c89..ef658e079 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -295,7 +295,8 @@ defmodule Pleroma.Web.AdminAPI.Config do @spec is_module_name?(String.t()) :: boolean() def is_module_name?(string) do - Regex.match?(~r/^(Pleroma|Phoenix|Tesla)\./, string) or string in ["Oban", "Ueberauth"] + Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack)\./, string) or + string in ["Oban", "Ueberauth", "ExSyslogger"] end defp do_eval(entity) do -- cgit v1.2.3 From 0b020403276519da84dce51053240ac6637eb1b3 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 25 Dec 2019 15:31:51 +0300 Subject: little fixes and typos fix --- lib/pleroma/web/admin_api/config.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index ef658e079..b55851602 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -183,6 +183,11 @@ defmodule Pleroma.Web.AdminAPI.Config do defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity), do: entity + defp do_convert(entity) + when is_atom(entity) and entity in [:"tlsv1.1", :"tlsv1.2", :"tlsv1.3"] do + ":#{to_string(entity)}" + end + defp do_convert(entity) when is_atom(entity), do: inspect(entity) defp do_convert(entity) when is_binary(entity), do: entity -- cgit v1.2.3 From c841174de820c891929b206e3eb2604cb6368ae6 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 26 Dec 2019 10:05:30 +0300 Subject: flag for delete fix --- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 23dcbedba..d12ed459d 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -815,7 +815,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do with :ok <- check_dynamic_configuration(conn) do updated = Enum.map(configs, fn - %{"group" => group, "key" => key, "delete" => "true"} = params -> + %{"group" => group, "key" => key, "delete" => true} = params -> with {:ok, config} <- Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) do config -- cgit v1.2.3 From 88a16bb9fcd1f80b8a2634e815cb855d3a8346ee Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Mon, 6 Jan 2020 14:05:32 +0300 Subject: deep merge in config update --- lib/pleroma/web/admin_api/config.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index b55851602..a01c28716 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -81,7 +81,7 @@ defmodule Pleroma.Web.AdminAPI.Config do old_value <- from_binary(config.value), transformed_value <- do_transform(params[:value]), {:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config}, - new_value <- Keyword.merge(old_value, transformed_value) do + new_value <- DeepMerge.deep_merge(old_value, transformed_value) do Config.update(config, %{value: new_value, transformed?: true}) else {reason, false, config} when reason in [:partial_update, :can_be_merged] -> -- cgit v1.2.3 From 958d0452e4e52f44301e4d9211fc965c1c184363 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 10 Jan 2020 18:18:09 +0300 Subject: fix for pleroma assets group update --- lib/pleroma/web/admin_api/config.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index a01c28716..49f0f8223 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -48,6 +48,7 @@ defmodule Pleroma.Web.AdminAPI.Config do @full_key_update [ {:pleroma, :ecto_repos}, + {:pleroma, :assets}, {:quack, :meta}, {:mime, :types}, {:cors_plug, [:max_age, :methods, :expose, :headers]}, -- cgit v1.2.3 From 7d128ca2083d83486a05d8c4456aa4090006e781 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 10 Jan 2020 19:34:19 +0300 Subject: dynamic_configuration renaming and moving it from instance settings --- lib/mix/tasks/pleroma/config.ex | 5 +++-- lib/pleroma/config/transfer_task.ex | 2 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 10 +++++----- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 257a0dfe5..3f80af5a7 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -30,7 +30,7 @@ defmodule Mix.Tasks.Pleroma.Config do def run(["migrate_to_db"]) do start_pleroma() - if Pleroma.Config.get([:instance, :dynamic_configuration]) do + if Pleroma.Config.get([:configurable_from_database]) do Enum.each(@groups, &load_and_create(&1)) else Mix.shell().info( @@ -48,7 +48,8 @@ defmodule Mix.Tasks.Pleroma.Config do aliases: [d: :delete_from_db] ) - with {:active?, true} <- {:active?, Pleroma.Config.get([:instance, :dynamic_configuration])}, + with {:active?, true} <- + {:active?, Pleroma.Config.get([:configurable_from_database])}, env_path when is_binary(env_path) <- opts[:env], config_path <- "config/#{env_path}.exported_from_db.secret.exs", {:ok, file} <- File.open(config_path, [:write, :utf8]) do diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index c89c1fcc8..75c4aa739 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Config.TransferTask do end def load_and_update_env do - with true <- Pleroma.Config.get([:instance, :dynamic_configuration]), + with true <- Pleroma.Config.get([:configurable_from_database]), true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"), started_applications <- Application.started_applications() do # We need to restart applications for loaded settings take effect diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index d12ed459d..849641113 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -785,7 +785,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def migrate_from_db(conn, _params) do - with :ok <- check_dynamic_configuration(conn) do + with :ok <- configurable_from_database(conn) do Mix.Tasks.Pleroma.Config.run([ "migrate_from_db", "--env", @@ -798,7 +798,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def config_show(conn, _params) do - with :ok <- check_dynamic_configuration(conn) do + with :ok <- configurable_from_database(conn) do configs = Pleroma.Repo.all(Config) if configs == [] do @@ -812,7 +812,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def config_update(conn, %{"configs" => configs}) do - with :ok <- check_dynamic_configuration(conn) do + with :ok <- configurable_from_database(conn) do updated = Enum.map(configs, fn %{"group" => group, "key" => key, "delete" => true} = params -> @@ -843,8 +843,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end - defp check_dynamic_configuration(conn) do - if Pleroma.Config.get([:instance, :dynamic_configuration]) do + defp configurable_from_database(conn) do + if Pleroma.Config.get([:configurable_from_database]) do :ok else errors(conn, {:error, "To use this endpoint you need to enable dynamic configuration."}) -- cgit v1.2.3 From eadb674c41dea27346aad43fa5514aa4f461273b Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 10 Jan 2020 19:44:30 +0300 Subject: don't migrate configurable_from_database setting --- lib/mix/tasks/pleroma/config.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 3f80af5a7..e7c6e8810 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -76,7 +76,8 @@ defmodule Mix.Tasks.Pleroma.Config do group |> Application.get_all_env() |> Enum.reject(fn {k, _v} -> - k in [Pleroma.Repo, :env] or (group == :phoenix and k == :serve_endpoints) + k in [Pleroma.Repo, :env, :configurable_from_database] or + (group == :phoenix and k == :serve_endpoints) end) |> Enum.each(fn {key, value} -> key = inspect(key) -- cgit v1.2.3 From d933fd3d61df2f9c346ab08fb2c95ddc12803858 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 10 Jan 2020 19:49:40 +0300 Subject: more renamings --- lib/pleroma/web/admin_api/admin_api_controller.ex | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 849641113..a13dd4775 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -802,7 +802,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do configs = Pleroma.Repo.all(Config) if configs == [] do - errors(conn, {:error, "To use dynamic configuration migrate your settings to database."}) + errors( + conn, + {:error, "To use configuration from database migrate your settings to database."} + ) else conn |> put_view(ConfigView) @@ -847,7 +850,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do if Pleroma.Config.get([:configurable_from_database]) do :ok else - errors(conn, {:error, "To use this endpoint you need to enable dynamic configuration."}) + errors( + conn, + {:error, "To use this endpoint you need to enable configuration from database."} + ) end end -- cgit v1.2.3 From 3453b27015dfa26bc6fd59899541eadfce2cacee Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 10 Jan 2020 21:24:06 +0300 Subject: don't migrate prometheus settings --- lib/mix/tasks/pleroma/config.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index e7c6e8810..b69c49b45 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -21,7 +21,6 @@ defmodule Mix.Tasks.Pleroma.Config do :auto_linker, :esshd, :ueberauth, - :prometheus, :http_signatures, :web_push_encryption, :joken -- cgit v1.2.3 From 0c9c62509d10c19e2e6d796cb431f1560e9e88b1 Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Sat, 11 Jan 2020 17:19:54 +0000 Subject: Remove MDII uploader --- lib/pleroma/uploaders/mdii.ex | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 lib/pleroma/uploaders/mdii.ex (limited to 'lib') diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex deleted file mode 100644 index c36f3d61d..000000000 --- a/lib/pleroma/uploaders/mdii.ex +++ /dev/null @@ -1,37 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Uploaders.MDII do - @moduledoc "Represents uploader for https://github.com/hakaba-hitoyo/minimal-digital-image-infrastructure" - - alias Pleroma.Config - alias Pleroma.HTTP - - @behaviour Pleroma.Uploaders.Uploader - - # MDII-hosted images are never passed through the MediaPlug; only local media. - # Delegate to Pleroma.Uploaders.Local - def get_file(file) do - Pleroma.Uploaders.Local.get_file(file) - end - - def put_file(upload) do - cgi = Config.get([Pleroma.Uploaders.MDII, :cgi]) - files = Config.get([Pleroma.Uploaders.MDII, :files]) - - {:ok, file_data} = File.read(upload.tempfile) - - extension = String.split(upload.name, ".") |> List.last() - query = "#{cgi}?#{extension}" - - with {:ok, %{status: 200, body: body}} <- - HTTP.post(query, file_data, [], adapter: [pool: :default]) do - remote_file_name = String.split(body) |> List.first() - public_url = "#{files}/#{remote_file_name}.#{extension}" - {:ok, {:url, public_url}} - else - _ -> Pleroma.Uploaders.Local.put_file(upload) - end - end -end -- cgit v1.2.3 From 88f0eed0f24cb05949edcea49215ee939babac58 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 12 Jan 2020 18:48:58 +0000 Subject: Delete attachments when status is deleted --- lib/pleroma/object.ex | 88 +++++++++++++++++++++++++++++++++++++++ lib/pleroma/uploaders/local.ex | 13 ++++++ lib/pleroma/uploaders/s3.ex | 14 +++++++ lib/pleroma/uploaders/uploader.ex | 3 +- 4 files changed, 117 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index eb37b95a6..2452a7389 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -17,6 +17,8 @@ defmodule Pleroma.Object do require Logger + @type t() :: %__MODULE__{} + schema "objects" do field(:data, :map) @@ -79,6 +81,20 @@ defmodule Pleroma.Object do Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id))) end + @doc """ + Get a single attachment by it's name and href + """ + @spec get_attachment_by_name_and_href(String.t(), String.t()) :: Object.t() | nil + def get_attachment_by_name_and_href(name, href) do + query = + from(o in Object, + where: fragment("(?)->>'name' = ?", o.data, ^name), + where: fragment("(?)->>'href' = ?", o.data, ^href) + ) + + Repo.one(query) + end + defp warn_on_no_object_preloaded(ap_id) do "Object.normalize() called without preloaded object (#{inspect(ap_id)}). Consider preloading the object" |> Logger.debug() @@ -164,6 +180,7 @@ defmodule Pleroma.Object do def delete(%Object{data: %{"id" => id}} = object) do with {:ok, _obj} = swap_object_with_tombstone(object), + :ok <- delete_attachments(object), deleted_activity = Activity.delete_all_by_object_ap_id(id), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do @@ -171,6 +188,77 @@ defmodule Pleroma.Object do end end + defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" => actor}}) do + hrefs = + Enum.flat_map(attachments, fn attachment -> + Enum.map(attachment["url"], & &1["href"]) + end) + + names = Enum.map(attachments, & &1["name"]) + + uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) + + # find all objects for copies of the attachments, name and actor doesn't matter here + delete_ids = + from(o in Object, + where: + fragment( + "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href'))::jsonb \\?| (?)", + o.data, + ^hrefs + ) + ) + |> Repo.all() + # we should delete 1 object for any given attachment, but don't delete files if + # there are more than 1 object for it + |> Enum.reduce(%{}, fn %{ + id: id, + data: %{ + "url" => [%{"href" => href}], + "actor" => obj_actor, + "name" => name + } + }, + acc -> + Map.update(acc, href, %{id: id, count: 1}, fn val -> + case obj_actor == actor and name in names do + true -> + # set id of the actor's object that will be deleted + %{val | id: id, count: val.count + 1} + + false -> + # another actor's object, just increase count to not delete file + %{val | count: val.count + 1} + end + end) + end) + |> Enum.map(fn {href, %{id: id, count: count}} -> + # only delete files that have single instance + with 1 <- count do + prefix = + case Pleroma.Config.get([Pleroma.Upload, :base_url]) do + nil -> "media" + _ -> "" + end + + base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url()) + + file_path = String.trim_leading(href, "#{base_url}/#{prefix}") + + uploader.delete_file(file_path) + end + + id + end) + + from(o in Object, where: o.id in ^delete_ids) + |> Repo.delete_all() + + :ok + end + + defp delete_attachments(%{data: _data}), do: :ok + def prune(%Object{data: %{"id" => id}} = object) do with {:ok, object} <- Repo.delete(object), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), diff --git a/lib/pleroma/uploaders/local.ex b/lib/pleroma/uploaders/local.ex index 36b3c35ec..2e6fe3292 100644 --- a/lib/pleroma/uploaders/local.ex +++ b/lib/pleroma/uploaders/local.ex @@ -5,10 +5,12 @@ defmodule Pleroma.Uploaders.Local do @behaviour Pleroma.Uploaders.Uploader + @impl true def get_file(_) do {:ok, {:static_dir, upload_path()}} end + @impl true def put_file(upload) do {local_path, file} = case Enum.reverse(Path.split(upload.path)) do @@ -33,4 +35,15 @@ defmodule Pleroma.Uploaders.Local do def upload_path do Pleroma.Config.get!([__MODULE__, :uploads]) end + + @impl true + def delete_file(path) do + upload_path() + |> Path.join(path) + |> File.rm() + |> case do + :ok -> :ok + {:error, posix_error} -> {:error, to_string(posix_error)} + end + end end diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex index 9876b6398..feb89cea6 100644 --- a/lib/pleroma/uploaders/s3.ex +++ b/lib/pleroma/uploaders/s3.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Uploaders.S3 do # The file name is re-encoded with S3's constraints here to comply with previous # links with less strict filenames + @impl true def get_file(file) do config = Config.get([__MODULE__]) bucket = Keyword.fetch!(config, :bucket) @@ -35,6 +36,7 @@ defmodule Pleroma.Uploaders.S3 do ])}} end + @impl true def put_file(%Pleroma.Upload{} = upload) do config = Config.get([__MODULE__]) bucket = Keyword.get(config, :bucket) @@ -69,6 +71,18 @@ defmodule Pleroma.Uploaders.S3 do end end + @impl true + def delete_file(file) do + [__MODULE__, :bucket] + |> Config.get() + |> ExAws.S3.delete_object(file) + |> ExAws.request() + |> case do + {:ok, %{status_code: 204}} -> :ok + error -> {:error, inspect(error)} + end + end + @regex Regex.compile!("[^0-9a-zA-Z!.*/'()_-]") def strict_encode(name) do String.replace(name, @regex, "-") diff --git a/lib/pleroma/uploaders/uploader.ex b/lib/pleroma/uploaders/uploader.ex index c0b22c28a..d71e213d2 100644 --- a/lib/pleroma/uploaders/uploader.ex +++ b/lib/pleroma/uploaders/uploader.ex @@ -36,6 +36,8 @@ defmodule Pleroma.Uploaders.Uploader do @callback put_file(Pleroma.Upload.t()) :: :ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback + @callback delete_file(file :: String.t()) :: :ok | {:error, String.t()} + @callback http_callback(Plug.Conn.t(), Map.t()) :: {:ok, Plug.Conn.t()} | {:ok, Plug.Conn.t(), file_spec()} @@ -43,7 +45,6 @@ defmodule Pleroma.Uploaders.Uploader do @optional_callbacks http_callback: 2 @spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()} - def put_file(uploader, upload) do case uploader.put_file(upload) do :ok -> {:ok, {:file, upload.path}} -- cgit v1.2.3 From 2ee6754095f5b81807efe97c73ada42e2c990ede Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 14 Jan 2020 17:24:26 +0100 Subject: Mix Tasks: Add pleroma.benchmarks.tags --- lib/mix/tasks/pleroma/benchmarks/tags.ex | 57 ++++++++++++++++++++++ .../controllers/timeline_controller.ex | 14 ++++-- 2 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 lib/mix/tasks/pleroma/benchmarks/tags.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/benchmarks/tags.ex b/lib/mix/tasks/pleroma/benchmarks/tags.ex new file mode 100644 index 000000000..73796b5f9 --- /dev/null +++ b/lib/mix/tasks/pleroma/benchmarks/tags.ex @@ -0,0 +1,57 @@ +defmodule Mix.Tasks.Pleroma.Benchmarks.Tags do + use Mix.Task + alias Pleroma.Repo + alias Pleroma.LoadTesting.Generator + import Ecto.Query + + def run(_args) do + Mix.Pleroma.start_pleroma() + activities_count = Repo.aggregate(from(a in Pleroma.Activity), :count, :id) + + if activities_count == 0 do + IO.puts("Did not find any activities, cleaning and generating") + clean_tables() + Generator.generate_users(users_max: 10) + Generator.generate_tagged_activities() + else + IO.puts("Found #{activities_count} activities, won't generate new ones") + end + + tags = Enum.map(0..20, fn i -> {"For #tag_#{i}", "tag_#{i}"} end) + + Enum.each(tags, fn {_, tag} -> + query = + from(o in Pleroma.Object, + where: fragment("(?)->'tag' \\? (?)", o.data, ^tag) + ) + + count = Repo.aggregate(query, :count, :id) + IO.puts("Database contains #{count} posts tagged with #{tag}") + end) + + user = Repo.all(Pleroma.User) |> List.first() + + Benchee.run( + %{ + "Hashtag fetching" => fn tag -> + Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching( + %{ + "tag" => tag + }, + user, + false + ) + end + }, + inputs: tags, + time: 5 + ) + end + + defp clean_tables do + IO.puts("Deleting old data...\n") + Ecto.Adapters.SQL.query!(Repo, "TRUNCATE users CASCADE;") + Ecto.Adapters.SQL.query!(Repo, "TRUNCATE activities CASCADE;") + Ecto.Adapters.SQL.query!(Repo, "TRUNCATE objects CASCADE;") + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 384159336..29964a1d4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -77,10 +77,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> render("index.json", activities: activities, for: user, as: :activity) end - # GET /api/v1/timelines/tag/:tag - def hashtag(%{assigns: %{user: user}} = conn, params) do - local_only = truthy_param?(params["local"]) - + def hashtag_fetching(params, user, local_only) do tags = [params["tag"], params["any"]] |> List.flatten() @@ -98,7 +95,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.get("none", []) |> Enum.map(&String.downcase(&1)) - activities = + _activities = params |> Map.put("type", "Create") |> Map.put("local_only", local_only) @@ -109,6 +106,13 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.put("tag_all", tag_all) |> Map.put("tag_reject", tag_reject) |> ActivityPub.fetch_public_activities() + end + + # GET /api/v1/timelines/tag/:tag + def hashtag(%{assigns: %{user: user}} = conn, params) do + local_only = truthy_param?(params["local"]) + + activities = hashtag_fetching(params, user, local_only) conn |> add_link_headers(activities, %{"local" => local_only}) -- cgit v1.2.3 From 0709757e47a546225163482474a46e8bc3d09837 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 14 Jan 2020 19:53:28 +0300 Subject: Check if object->data is array when looking up attachment objects to delete --- lib/pleroma/object.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 2452a7389..6c56a9c62 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -203,7 +203,8 @@ defmodule Pleroma.Object do from(o in Object, where: fragment( - "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href'))::jsonb \\?| (?)", + "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)", + o.data, o.data, ^hrefs ) -- cgit v1.2.3 From 76c1948880687ed74e0275e51808c0ddc6be887d Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 15 Jan 2020 12:11:23 +0300 Subject: [#1478] Adjusted AdminAPIController admin subscope requirements. --- lib/pleroma/web/admin_api/admin_api_controller.ex | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index c8abeff06..529169c1b 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -32,19 +32,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, %{scopes: ["read:accounts"], admin: true} - when action in [:list_users, :user_show, :right_get, :invites] + when action in [:list_users, :user_show, :right_get] ) plug( OAuthScopesPlug, %{scopes: ["write:accounts"], admin: true} when action in [ - :get_invite_token, - :revoke_invite, - :email_invite, :get_password_reset, - :user_follow, - :user_unfollow, :user_delete, :users_create, :user_toggle_activation, @@ -57,6 +52,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ] ) + plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites) + + plug( + OAuthScopesPlug, + %{scopes: ["write:invites"], admin: true} + when action in [:create_invite_token, :revoke_invite, :email_invite] + ) + + plug( + OAuthScopesPlug, + %{scopes: ["write:follows"], admin: true} + when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow] + ) + plug( OAuthScopesPlug, %{scopes: ["read:reports"], admin: true} @@ -90,7 +99,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, %{scopes: ["write"], admin: true} - when action in [:relay_follow, :relay_unfollow, :config_update] + when action == :config_update ) @users_page_size 50 -- cgit v1.2.3 From 167e9c45eccf5ddb89077c979b1d587318f78cc0 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 15 Jan 2020 12:37:50 +0100 Subject: Benchmarks: Move to correct folder --- lib/mix/tasks/pleroma/benchmarks/tags.ex | 57 -------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 lib/mix/tasks/pleroma/benchmarks/tags.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/benchmarks/tags.ex b/lib/mix/tasks/pleroma/benchmarks/tags.ex deleted file mode 100644 index 73796b5f9..000000000 --- a/lib/mix/tasks/pleroma/benchmarks/tags.ex +++ /dev/null @@ -1,57 +0,0 @@ -defmodule Mix.Tasks.Pleroma.Benchmarks.Tags do - use Mix.Task - alias Pleroma.Repo - alias Pleroma.LoadTesting.Generator - import Ecto.Query - - def run(_args) do - Mix.Pleroma.start_pleroma() - activities_count = Repo.aggregate(from(a in Pleroma.Activity), :count, :id) - - if activities_count == 0 do - IO.puts("Did not find any activities, cleaning and generating") - clean_tables() - Generator.generate_users(users_max: 10) - Generator.generate_tagged_activities() - else - IO.puts("Found #{activities_count} activities, won't generate new ones") - end - - tags = Enum.map(0..20, fn i -> {"For #tag_#{i}", "tag_#{i}"} end) - - Enum.each(tags, fn {_, tag} -> - query = - from(o in Pleroma.Object, - where: fragment("(?)->'tag' \\? (?)", o.data, ^tag) - ) - - count = Repo.aggregate(query, :count, :id) - IO.puts("Database contains #{count} posts tagged with #{tag}") - end) - - user = Repo.all(Pleroma.User) |> List.first() - - Benchee.run( - %{ - "Hashtag fetching" => fn tag -> - Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching( - %{ - "tag" => tag - }, - user, - false - ) - end - }, - inputs: tags, - time: 5 - ) - end - - defp clean_tables do - IO.puts("Deleting old data...\n") - Ecto.Adapters.SQL.query!(Repo, "TRUNCATE users CASCADE;") - Ecto.Adapters.SQL.query!(Repo, "TRUNCATE activities CASCADE;") - Ecto.Adapters.SQL.query!(Repo, "TRUNCATE objects CASCADE;") - end -end -- cgit v1.2.3 From 66de2b159b2e03fcac7fece01d39e1238e02dbf7 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Wed, 15 Jan 2020 17:08:45 +0300 Subject: don't migrate Pleroma.Web.EndPoint settings don't set Logger level to all tasks --- lib/mix/pleroma.ex | 7 ++++--- lib/mix/tasks/pleroma/config.ex | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index 73a076a53..ea9923440 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -4,11 +4,12 @@ defmodule Mix.Pleroma do @doc "Common functions to be reused in mix tasks" - def start_pleroma do + def start_pleroma(change_logger_level \\ true) do Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) - if Pleroma.Config.get(:env) != :test do - Application.put_env(:logger, :console, level: :debug) + if Pleroma.Config.get(:env) != :test and change_logger_level do + require Logger + Logger.configure(level: :debug) end {:ok, _} = Application.ensure_all_started(:pleroma) diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index b69c49b45..92487dd51 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -27,7 +27,8 @@ defmodule Mix.Tasks.Pleroma.Config do ] def run(["migrate_to_db"]) do - start_pleroma() + # we want to save original logger level + start_pleroma(false) if Pleroma.Config.get([:configurable_from_database]) do Enum.each(@groups, &load_and_create(&1)) @@ -75,7 +76,7 @@ defmodule Mix.Tasks.Pleroma.Config do group |> Application.get_all_env() |> Enum.reject(fn {k, _v} -> - k in [Pleroma.Repo, :env, :configurable_from_database] or + k in [Pleroma.Repo, Pleroma.Web.Endpoint, :env, :configurable_from_database] or (group == :phoenix and k == :serve_endpoints) end) |> Enum.each(fn {key, value} -> -- cgit v1.2.3 From 59ba5c80b97b3cef2286716573d9697e82dd2a94 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Wed, 15 Jan 2020 17:10:33 +0300 Subject: little cleanup --- lib/pleroma/config/transfer_task.ex | 2 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 75c4aa739..56abfe2a5 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Config.TransferTask do end def load_and_update_env do - with true <- Pleroma.Config.get([:configurable_from_database]), + with true <- Pleroma.Config.get(:configurable_from_database), true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"), started_applications <- Application.started_applications() do # We need to restart applications for loaded settings take effect diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index ce5411e8a..99fcc080c 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -847,7 +847,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end defp configurable_from_database(conn) do - if Pleroma.Config.get([:configurable_from_database]) do + if Pleroma.Config.get(:configurable_from_database) do :ok else errors( -- cgit v1.2.3 From 29155137fdae15fccfaa68fb9c954e98078ce0c4 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 16 Jan 2020 08:50:27 +0300 Subject: renaming Pleroma.Web.AdminAPI.Config -> Pleroma.ConfigDB --- lib/mix/tasks/pleroma/config.ex | 8 +- lib/pleroma/config/config_db.ex | 312 ++++++++++++++++++++++ lib/pleroma/config/transfer_task.ex | 14 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 8 +- lib/pleroma/web/admin_api/config.ex | 312 ---------------------- lib/pleroma/web/admin_api/views/config_view.ex | 2 +- 6 files changed, 328 insertions(+), 328 deletions(-) create mode 100644 lib/pleroma/config/config_db.ex delete mode 100644 lib/pleroma/web/admin_api/config.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 92487dd51..57952aeba 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -5,8 +5,8 @@ defmodule Mix.Tasks.Pleroma.Config do use Mix.Task import Mix.Pleroma + alias Pleroma.ConfigDB alias Pleroma.Repo - alias Pleroma.Web.AdminAPI.Config @shortdoc "Manages the location of the config" @moduledoc File.read!("docs/administration/CLI_tasks/config.md") @@ -55,7 +55,7 @@ defmodule Mix.Tasks.Pleroma.Config do {:ok, file} <- File.open(config_path, [:write, :utf8]) do IO.write(file, "use Mix.Config\r\n") - Config + ConfigDB |> Repo.all() |> Enum.each(&write_to_file_with_deletion(&1, file, opts[:delete_from_db])) @@ -81,7 +81,7 @@ defmodule Mix.Tasks.Pleroma.Config do end) |> Enum.each(fn {key, value} -> key = inspect(key) - {:ok, _} = Config.update_or_create(%{group: inspect(group), key: key, value: value}) + {:ok, _} = ConfigDB.update_or_create(%{group: inspect(group), key: key, value: value}) Mix.shell().info("settings for key #{key} migrated.") end) @@ -93,7 +93,7 @@ defmodule Mix.Tasks.Pleroma.Config do IO.write( file, "config #{config.group}, #{config.key}, #{ - inspect(Config.from_binary(config.value), limit: :infinity) + inspect(ConfigDB.from_binary(config.value), limit: :infinity) }\r\n\r\n" ) diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex new file mode 100644 index 000000000..e433ce442 --- /dev/null +++ b/lib/pleroma/config/config_db.ex @@ -0,0 +1,312 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ConfigDB do + use Ecto.Schema + import Ecto.Changeset + import Pleroma.Web.Gettext + alias __MODULE__ + alias Pleroma.Repo + + @type t :: %__MODULE__{} + + schema "config" do + field(:key, :string) + field(:group, :string) + field(:value, :binary) + + timestamps() + end + + @spec get_by_params(map()) :: ConfigDB.t() | nil + def get_by_params(params), do: Repo.get_by(ConfigDB, params) + + @spec changeset(ConfigDB.t(), map()) :: Changeset.t() + def changeset(config, params \\ %{}) do + params = Map.put(params, :value, transform(params[:value])) + + config + |> cast(params, [:key, :group, :value]) + |> validate_required([:key, :group, :value]) + |> unique_constraint(:key, name: :config_group_key_index) + end + + @spec create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} + def create(params) do + %ConfigDB{} + |> changeset(params) + |> Repo.insert() + end + + @spec update(ConfigDB.t(), map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} + def update(%ConfigDB{} = config, %{value: value}) do + config + |> changeset(%{value: value}) + |> Repo.update() + end + + @full_key_update [ + {:pleroma, :ecto_repos}, + {:pleroma, :assets}, + {:quack, :meta}, + {:mime, :types}, + {:cors_plug, [:max_age, :methods, :expose, :headers]}, + {:auto_linker, :opts}, + {:swarm, :node_blacklist}, + {:logger, :backends} + ] + + defp only_full_update?(%ConfigDB{} = config) do + config_group = ConfigDB.from_string(config.group) + config_key = ConfigDB.from_string(config.key) + + Enum.any?(@full_key_update, fn + {group, key} when is_list(key) -> + config_group == group and config_key in key + + {group, key} -> + config_group == group and config_key == key + end) + end + + defp can_be_partially_updated?(%ConfigDB{} = config), do: not only_full_update?(config) + + @spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} + def update_or_create(params) do + search_opts = Map.take(params, [:group, :key]) + + with %ConfigDB{} = config <- ConfigDB.get_by_params(search_opts), + {:partial_update, true, config} <- + {:partial_update, can_be_partially_updated?(config), config}, + old_value <- from_binary(config.value), + transformed_value <- do_transform(params[:value]), + {:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config}, + new_value <- DeepMerge.deep_merge(old_value, transformed_value) do + ConfigDB.update(config, %{value: new_value, transformed?: true}) + else + {reason, false, config} when reason in [:partial_update, :can_be_merged] -> + ConfigDB.update(config, params) + + nil -> + ConfigDB.create(params) + end + end + + @spec delete(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} | {:ok, nil} + def delete(params) do + search_opts = Map.delete(params, :subkeys) + + with %ConfigDB{} = config <- ConfigDB.get_by_params(search_opts), + {config, sub_keys} when is_list(sub_keys) <- {config, params[:subkeys]}, + old_value <- from_binary(config.value), + keys <- Enum.map(sub_keys, &do_transform_string(&1)), + new_value <- Keyword.drop(old_value, keys) do + ConfigDB.update(config, %{value: new_value}) + else + {config, nil} -> + Repo.delete(config) + {:ok, nil} + + nil -> + err = + dgettext("errors", "Config with params %{params} not found", params: inspect(params)) + + {:error, err} + end + end + + @spec from_binary(binary()) :: term() + def from_binary(binary), do: :erlang.binary_to_term(binary) + + @spec from_binary_with_convert(binary()) :: any() + def from_binary_with_convert(binary) do + binary + |> from_binary() + |> do_convert() + end + + @spec from_string(String.t()) :: atom() | no_return() + def from_string(":" <> entity), do: String.to_existing_atom(entity) + + def from_string(entity) when is_binary(entity) do + if is_module_name?(entity) do + String.to_existing_atom("Elixir.#{entity}") + else + entity + end + end + + defp do_convert(entity) when is_list(entity) do + for v <- entity, into: [], do: do_convert(v) + end + + defp do_convert(%Regex{} = entity), do: inspect(entity) + + defp do_convert(entity) when is_map(entity) do + for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)} + end + + defp do_convert({:proxy_url, {type, :localhost, port}}) do + %{"tuple" => [":proxy_url", %{"tuple" => [do_convert(type), "localhost", port]}]} + end + + defp do_convert({:proxy_url, {type, host, port}}) when is_tuple(host) do + ip = + host + |> :inet_parse.ntoa() + |> to_string() + + %{ + "tuple" => [ + ":proxy_url", + %{"tuple" => [do_convert(type), ip, port]} + ] + } + end + + defp do_convert({:proxy_url, {type, host, port}}) do + %{ + "tuple" => [ + ":proxy_url", + %{"tuple" => [do_convert(type), to_string(host), port]} + ] + } + end + + defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]} + # TODO: will become useless after removing hackney + defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]} + + defp do_convert(entity) when is_tuple(entity), + do: %{"tuple" => do_convert(Tuple.to_list(entity))} + + defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity), + do: entity + + defp do_convert(entity) + when is_atom(entity) and entity in [:"tlsv1.1", :"tlsv1.2", :"tlsv1.3"] do + ":#{to_string(entity)}" + end + + defp do_convert(entity) when is_atom(entity), do: inspect(entity) + + defp do_convert(entity) when is_binary(entity), do: entity + + @spec transform(any()) :: binary() | no_return() + def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do + entity + |> do_transform() + |> to_binary() + end + + def transform(entity), do: to_binary(entity) + + @spec to_binary(any()) :: binary() + def to_binary(entity), do: :erlang.term_to_binary(entity) + + defp do_transform(%Regex{} = entity), do: entity + + defp do_transform(%{"tuple" => [":proxy_url", %{"tuple" => [type, host, port]}]}) do + {:proxy_url, {do_transform_string(type), parse_host(host), port}} + end + + defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do + {dispatch_settings, []} = do_eval(entity) + {:dispatch, [dispatch_settings]} + end + + # TODO: will become useless after removing hackney + defp do_transform(%{"tuple" => [":partial_chain", entity]}) do + {partial_chain, []} = do_eval(entity) + {:partial_chain, partial_chain} + end + + defp do_transform(%{"tuple" => entity}) do + Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end) + end + + defp do_transform(entity) when is_map(entity) do + for {k, v} <- entity, into: %{}, do: {do_transform(k), do_transform(v)} + end + + defp do_transform(entity) when is_list(entity) do + for v <- entity, into: [], do: do_transform(v) + end + + defp do_transform(entity) when is_binary(entity) do + entity + |> String.trim() + |> do_transform_string() + end + + defp do_transform(entity), do: entity + + defp parse_host("localhost"), do: :localhost + + defp parse_host(host) do + charlist = to_charlist(host) + + case :inet.parse_address(charlist) do + {:error, :einval} -> + charlist + + {:ok, ip} -> + ip + end + end + + @delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}] + + defp find_valid_delimiter([], _string, _), + do: raise(ArgumentError, message: "valid delimiter for Regex expression not found") + + defp find_valid_delimiter([{leading, closing} = delimiter | others], pattern, regex_delimiter) + when is_tuple(delimiter) do + if String.contains?(pattern, closing) do + find_valid_delimiter(others, pattern, regex_delimiter) + else + {:ok, {leading, closing}} + end + end + + defp find_valid_delimiter([delimiter | others], pattern, regex_delimiter) do + if String.contains?(pattern, delimiter) do + find_valid_delimiter(others, pattern, regex_delimiter) + else + {:ok, {delimiter, delimiter}} + end + end + + @regex_parts ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u + + defp do_transform_string("~r" <> _pattern = regex) do + with %{"modifier" => modifier, "pattern" => pattern, "delimiter" => regex_delimiter} <- + Regex.named_captures(@regex_parts, regex), + {:ok, {leading, closing}} <- find_valid_delimiter(@delimiters, pattern, regex_delimiter), + {result, _} <- Code.eval_string("~r#{leading}#{pattern}#{closing}#{modifier}") do + result + end + end + + defp do_transform_string(":" <> atom), do: String.to_atom(atom) + + defp do_transform_string(value) do + if is_module_name?(value) do + String.to_existing_atom("Elixir." <> value) + else + value + end + end + + @spec is_module_name?(String.t()) :: boolean() + def is_module_name?(string) do + Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack)\./, string) or + string in ["Oban", "Ueberauth", "ExSyslogger"] + end + + defp do_eval(entity) do + cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "") + Code.eval_string(cleaned_string) + end +end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 56abfe2a5..b39f9594e 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -5,10 +5,10 @@ defmodule Pleroma.Config.TransferTask do use Task - require Logger - + alias Pleroma.ConfigDB alias Pleroma.Repo - alias Pleroma.Web.AdminAPI.Config + + require Logger def start_link(_) do load_and_update_env() @@ -21,7 +21,7 @@ defmodule Pleroma.Config.TransferTask do true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"), started_applications <- Application.started_applications() do # We need to restart applications for loaded settings take effect - Config + ConfigDB |> Repo.all() |> Enum.map(&update_env(&1)) |> Enum.uniq() @@ -33,9 +33,9 @@ defmodule Pleroma.Config.TransferTask do defp update_env(setting) do try do - key = Config.from_string(setting.key) - group = Config.from_string(setting.group) - value = Config.from_binary(setting.value) + key = ConfigDB.from_string(setting.key) + group = ConfigDB.from_string(setting.group) + value = ConfigDB.from_binary(setting.value) if group != :phoenix and key != :serve_endpoints do :ok = Application.put_env(group, key, value) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 99fcc080c..e1d16c30b 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do import Pleroma.Web.ControllerHelper, only: [json_response: 3] alias Pleroma.Activity + alias Pleroma.ConfigDB alias Pleroma.ModerationLog alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.ReportNote @@ -17,7 +18,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.AdminAPI.AccountView - alias Pleroma.Web.AdminAPI.Config alias Pleroma.Web.AdminAPI.ConfigView alias Pleroma.Web.AdminAPI.ModerationLogView alias Pleroma.Web.AdminAPI.Report @@ -799,7 +799,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do def config_show(conn, _params) do with :ok <- configurable_from_database(conn) do - configs = Pleroma.Repo.all(Config) + configs = Pleroma.Repo.all(ConfigDB) if configs == [] do errors( @@ -820,13 +820,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do Enum.map(configs, fn %{"group" => group, "key" => key, "delete" => true} = params -> with {:ok, config} <- - Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) do + ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]}) do config end %{"group" => group, "key" => key, "value" => value} -> with {:ok, config} <- - Config.update_or_create(%{group: group, key: key, value: value}) do + ConfigDB.update_or_create(%{group: group, key: key, value: value}) do config end end) diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex deleted file mode 100644 index 49f0f8223..000000000 --- a/lib/pleroma/web/admin_api/config.ex +++ /dev/null @@ -1,312 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.Config do - use Ecto.Schema - import Ecto.Changeset - import Pleroma.Web.Gettext - alias __MODULE__ - alias Pleroma.Repo - - @type t :: %__MODULE__{} - - schema "config" do - field(:key, :string) - field(:group, :string) - field(:value, :binary) - - timestamps() - end - - @spec get_by_params(map()) :: Config.t() | nil - def get_by_params(params), do: Repo.get_by(Config, params) - - @spec changeset(Config.t(), map()) :: Changeset.t() - def changeset(config, params \\ %{}) do - params = Map.put(params, :value, transform(params[:value])) - - config - |> cast(params, [:key, :group, :value]) - |> validate_required([:key, :group, :value]) - |> unique_constraint(:key, name: :config_group_key_index) - end - - @spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def create(params) do - %Config{} - |> changeset(params) - |> Repo.insert() - end - - @spec update(Config.t(), map()) :: {:ok, Config} | {:error, Changeset.t()} - def update(%Config{} = config, %{value: value}) do - config - |> changeset(%{value: value}) - |> Repo.update() - end - - @full_key_update [ - {:pleroma, :ecto_repos}, - {:pleroma, :assets}, - {:quack, :meta}, - {:mime, :types}, - {:cors_plug, [:max_age, :methods, :expose, :headers]}, - {:auto_linker, :opts}, - {:swarm, :node_blacklist}, - {:logger, :backends} - ] - - defp only_full_update?(%Config{} = config) do - config_group = Config.from_string(config.group) - config_key = Config.from_string(config.key) - - Enum.any?(@full_key_update, fn - {group, key} when is_list(key) -> - config_group == group and config_key in key - - {group, key} -> - config_group == group and config_key == key - end) - end - - defp can_be_partially_updated?(%Config{} = config), do: not only_full_update?(config) - - @spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def update_or_create(params) do - search_opts = Map.take(params, [:group, :key]) - - with %Config{} = config <- Config.get_by_params(search_opts), - {:partial_update, true, config} <- - {:partial_update, can_be_partially_updated?(config), config}, - old_value <- from_binary(config.value), - transformed_value <- do_transform(params[:value]), - {:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config}, - new_value <- DeepMerge.deep_merge(old_value, transformed_value) do - Config.update(config, %{value: new_value, transformed?: true}) - else - {reason, false, config} when reason in [:partial_update, :can_be_merged] -> - Config.update(config, params) - - nil -> - Config.create(params) - end - end - - @spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} | {:ok, nil} - def delete(params) do - search_opts = Map.delete(params, :subkeys) - - with %Config{} = config <- Config.get_by_params(search_opts), - {config, sub_keys} when is_list(sub_keys) <- {config, params[:subkeys]}, - old_value <- from_binary(config.value), - keys <- Enum.map(sub_keys, &do_transform_string(&1)), - new_value <- Keyword.drop(old_value, keys) do - Config.update(config, %{value: new_value}) - else - {config, nil} -> - Repo.delete(config) - {:ok, nil} - - nil -> - err = - dgettext("errors", "Config with params %{params} not found", params: inspect(params)) - - {:error, err} - end - end - - @spec from_binary(binary()) :: term() - def from_binary(binary), do: :erlang.binary_to_term(binary) - - @spec from_binary_with_convert(binary()) :: any() - def from_binary_with_convert(binary) do - binary - |> from_binary() - |> do_convert() - end - - @spec from_string(String.t()) :: atom() | no_return() - def from_string(":" <> entity), do: String.to_existing_atom(entity) - - def from_string(entity) when is_binary(entity) do - if is_module_name?(entity) do - String.to_existing_atom("Elixir.#{entity}") - else - entity - end - end - - defp do_convert(entity) when is_list(entity) do - for v <- entity, into: [], do: do_convert(v) - end - - defp do_convert(%Regex{} = entity), do: inspect(entity) - - defp do_convert(entity) when is_map(entity) do - for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)} - end - - defp do_convert({:proxy_url, {type, :localhost, port}}) do - %{"tuple" => [":proxy_url", %{"tuple" => [do_convert(type), "localhost", port]}]} - end - - defp do_convert({:proxy_url, {type, host, port}}) when is_tuple(host) do - ip = - host - |> :inet_parse.ntoa() - |> to_string() - - %{ - "tuple" => [ - ":proxy_url", - %{"tuple" => [do_convert(type), ip, port]} - ] - } - end - - defp do_convert({:proxy_url, {type, host, port}}) do - %{ - "tuple" => [ - ":proxy_url", - %{"tuple" => [do_convert(type), to_string(host), port]} - ] - } - end - - defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]} - # TODO: will become useless after removing hackney - defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]} - - defp do_convert(entity) when is_tuple(entity), - do: %{"tuple" => do_convert(Tuple.to_list(entity))} - - defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity), - do: entity - - defp do_convert(entity) - when is_atom(entity) and entity in [:"tlsv1.1", :"tlsv1.2", :"tlsv1.3"] do - ":#{to_string(entity)}" - end - - defp do_convert(entity) when is_atom(entity), do: inspect(entity) - - defp do_convert(entity) when is_binary(entity), do: entity - - @spec transform(any()) :: binary() | no_return() - def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do - entity - |> do_transform() - |> to_binary() - end - - def transform(entity), do: to_binary(entity) - - @spec to_binary(any()) :: binary() - def to_binary(entity), do: :erlang.term_to_binary(entity) - - defp do_transform(%Regex{} = entity), do: entity - - defp do_transform(%{"tuple" => [":proxy_url", %{"tuple" => [type, host, port]}]}) do - {:proxy_url, {do_transform_string(type), parse_host(host), port}} - end - - defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do - {dispatch_settings, []} = do_eval(entity) - {:dispatch, [dispatch_settings]} - end - - # TODO: will become useless after removing hackney - defp do_transform(%{"tuple" => [":partial_chain", entity]}) do - {partial_chain, []} = do_eval(entity) - {:partial_chain, partial_chain} - end - - defp do_transform(%{"tuple" => entity}) do - Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end) - end - - defp do_transform(entity) when is_map(entity) do - for {k, v} <- entity, into: %{}, do: {do_transform(k), do_transform(v)} - end - - defp do_transform(entity) when is_list(entity) do - for v <- entity, into: [], do: do_transform(v) - end - - defp do_transform(entity) when is_binary(entity) do - entity - |> String.trim() - |> do_transform_string() - end - - defp do_transform(entity), do: entity - - defp parse_host("localhost"), do: :localhost - - defp parse_host(host) do - charlist = to_charlist(host) - - case :inet.parse_address(charlist) do - {:error, :einval} -> - charlist - - {:ok, ip} -> - ip - end - end - - @delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}] - - defp find_valid_delimiter([], _string, _), - do: raise(ArgumentError, message: "valid delimiter for Regex expression not found") - - defp find_valid_delimiter([{leading, closing} = delimiter | others], pattern, regex_delimiter) - when is_tuple(delimiter) do - if String.contains?(pattern, closing) do - find_valid_delimiter(others, pattern, regex_delimiter) - else - {:ok, {leading, closing}} - end - end - - defp find_valid_delimiter([delimiter | others], pattern, regex_delimiter) do - if String.contains?(pattern, delimiter) do - find_valid_delimiter(others, pattern, regex_delimiter) - else - {:ok, {delimiter, delimiter}} - end - end - - @regex_parts ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u - - defp do_transform_string("~r" <> _pattern = regex) do - with %{"modifier" => modifier, "pattern" => pattern, "delimiter" => regex_delimiter} <- - Regex.named_captures(@regex_parts, regex), - {:ok, {leading, closing}} <- find_valid_delimiter(@delimiters, pattern, regex_delimiter), - {result, _} <- Code.eval_string("~r#{leading}#{pattern}#{closing}#{modifier}") do - result - end - end - - defp do_transform_string(":" <> atom), do: String.to_atom(atom) - - defp do_transform_string(value) do - if is_module_name?(value) do - String.to_existing_atom("Elixir." <> value) - else - value - end - end - - @spec is_module_name?(String.t()) :: boolean() - def is_module_name?(string) do - Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack)\./, string) or - string in ["Oban", "Ueberauth", "ExSyslogger"] - end - - defp do_eval(entity) do - cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "") - Code.eval_string(cleaned_string) - end -end diff --git a/lib/pleroma/web/admin_api/views/config_view.ex b/lib/pleroma/web/admin_api/views/config_view.ex index 49add0b6e..72b042ab7 100644 --- a/lib/pleroma/web/admin_api/views/config_view.ex +++ b/lib/pleroma/web/admin_api/views/config_view.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do %{ key: config.key, group: config.group, - value: Pleroma.Web.AdminAPI.Config.from_binary_with_convert(config.value) + value: Pleroma.ConfigDB.from_binary_with_convert(config.value) } end end -- cgit v1.2.3 From 60ba2339a244290f7353e8026032b1a5d185227c Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 Jan 2020 11:45:44 +0300 Subject: saving to DB only added by user settings --- lib/mix/tasks/pleroma/config.ex | 65 +++++++++++++---------- lib/pleroma/config/config_db.ex | 18 +++++++ lib/pleroma/config/holder.ex | 51 ++++++++++++++++++ lib/pleroma/config/transfer_task.ex | 22 ++++++-- lib/pleroma/web/admin_api/admin_api_controller.ex | 42 ++++++++++++++- lib/pleroma/web/router.ex | 1 - 6 files changed, 166 insertions(+), 33 deletions(-) create mode 100644 lib/pleroma/config/holder.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 57952aeba..3157e7b20 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -4,42 +4,25 @@ defmodule Mix.Tasks.Pleroma.Config do use Mix.Task + import Mix.Pleroma + alias Pleroma.ConfigDB alias Pleroma.Repo + + require Logger + @shortdoc "Manages the location of the config" @moduledoc File.read!("docs/administration/CLI_tasks/config.md") - @groups [ - :pleroma, - :logger, - :quack, - :mime, - :tesla, - :phoenix, - :cors_plug, - :auto_linker, - :esshd, - :ueberauth, - :http_signatures, - :web_push_encryption, - :joken - ] - def run(["migrate_to_db"]) do # we want to save original logger level start_pleroma(false) - - if Pleroma.Config.get([:configurable_from_database]) do - Enum.each(@groups, &load_and_create(&1)) - else - Mix.shell().info( - "Migration is not allowed by config. You can change this behavior in instance settings." - ) - end + migrate_to_db() end def run(["migrate_from_db" | options]) do + # TODO: add support for releases start_pleroma() {opts, _} = @@ -72,10 +55,36 @@ defmodule Mix.Tasks.Pleroma.Config do end end - defp load_and_create(group) do - group - |> Application.get_all_env() - |> Enum.reject(fn {k, _v} -> + @spec migrate_to_db(Path.t() | nil) :: any() + def migrate_to_db(file_path \\ nil) do + if Pleroma.Config.get([:configurable_from_database]) do + # TODO: add support for releases + config_file = file_path || "config/#{Pleroma.Config.get(:env)}.secret.exs" + do_migrate_to_db(config_file) + else + Mix.shell().info( + "migration is not allowed by config. You can change this behavior in instance settings." + ) + end + end + + defp do_migrate_to_db(config_file) do + if File.exists?(config_file) do + {custom_config, _paths} = + if Code.ensure_loaded?(Config.Reader), + do: Config.Reader.read_imports!(config_file), + else: Mix.Config.eval!(config_file) + + custom_config + |> Keyword.keys() + |> Enum.each(&create(&1, custom_config[&1])) + else + Logger.warn("to migrate settings, you must define custom settings in #{config_file}") + end + end + + defp create(group, settings) do + Enum.reject(settings, fn {k, _v} -> k in [Pleroma.Repo, Pleroma.Web.Endpoint, :env, :configurable_from_database] or (group == :phoenix and k == :serve_endpoints) end) diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index e433ce442..294fbc3f0 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -5,6 +5,7 @@ defmodule Pleroma.ConfigDB do use Ecto.Schema import Ecto.Changeset + import Ecto.Query import Pleroma.Web.Gettext alias __MODULE__ alias Pleroma.Repo @@ -19,6 +20,20 @@ defmodule Pleroma.ConfigDB do timestamps() end + @spec get_all_as_keyword() :: keyword() + def get_all_as_keyword do + ConfigDB + |> select([c], {c.group, c.key, c.value}) + |> Repo.all() + |> Enum.reduce([], fn {group, key, value}, acc -> + group = ConfigDB.from_string(group) + key = ConfigDB.from_string(key) + value = from_binary(value) + + Keyword.update(acc, group, [{key, value}], &Keyword.merge(&1, [{key, value}])) + end) + end + @spec get_by_params(map()) :: ConfigDB.t() | nil def get_by_params(params), do: Repo.get_by(ConfigDB, params) @@ -137,6 +152,9 @@ defmodule Pleroma.ConfigDB do end end + @spec convert(any()) :: any() + def convert(entity), do: do_convert(entity) + defp do_convert(entity) when is_list(entity) do for v <- entity, into: [], do: do_convert(v) end diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex new file mode 100644 index 000000000..aa35382b2 --- /dev/null +++ b/lib/pleroma/config/holder.ex @@ -0,0 +1,51 @@ +defmodule Pleroma.Config.Loader do + # TODO: add support for releases + if Code.ensure_loaded?(Config.Reader) do + @spec load() :: map() + def load do + config = Config.Reader.read!("config/config.exs") + env_config = Config.Reader.read!("config/#{Mix.env()}.exs") + + Config.Reader.merge(config, env_config) + end + else + # support for Elixir less than 1.9 + @spec load() :: map() + def load do + config = Mix.Config.eval!("config/config.exs") + env_config = Mix.Config.eval!("config/#{Mix.env()}.exs") + + Mix.Config.merge(config, env_config) + end + end +end + +defmodule Pleroma.Config.Holder do + @config Pleroma.Config.Loader.load() + + @spec config() :: keyword() + def config do + @config + |> Keyword.keys() + |> Enum.map(&filter(&1, config(&1))) + |> List.flatten() + end + + @spec config(atom()) :: any() + def config(group), do: @config[group] + + @spec config(atom(), atom()) :: any() + def config(group, key), do: @config[group][key] + + defp filter(group, settings) when group not in [:swarm] do + filtered = + Enum.reject(settings, fn {k, _v} -> + k in [Pleroma.Repo, Pleroma.Web.Endpoint, :env, :configurable_from_database] or + (group == :phoenix and k == :serve_endpoints) + end) + + {group, filtered} + end + + defp filter(_, _), do: [] +end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index b39f9594e..828a297de 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -38,10 +38,18 @@ defmodule Pleroma.Config.TransferTask do value = ConfigDB.from_binary(setting.value) if group != :phoenix and key != :serve_endpoints do - :ok = Application.put_env(group, key, value) - end + default = Pleroma.Config.Holder.config(group, key) + + merged_value = + if can_be_merged?(default, value) do + DeepMerge.deep_merge(default, value) + else + value + end - group + :ok = Application.put_env(group, key, merged_value) + group + end rescue e -> Logger.warn( @@ -61,4 +69,12 @@ defmodule Pleroma.Config.TransferTask do error -> Logger.warn(inspect(error)) end end + + defp can_be_merged?(val1, val2) when is_map(val1) and is_map(val2), do: true + + defp can_be_merged?(val1, val2) when is_list(val1) and is_list(val2) do + Keyword.keyword?(val1) and Keyword.keyword?(val2) + end + + defp can_be_merged?(_val1, _val2), do: false end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index e1d16c30b..cc93c2309 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -797,7 +797,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end - def config_show(conn, _params) do + def config_show(conn, %{"only_db" => true}) do with :ok <- configurable_from_database(conn) do configs = Pleroma.Repo.all(ConfigDB) @@ -814,6 +814,46 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end + def config_show(conn, _params) do + with :ok <- configurable_from_database(conn) do + configs = ConfigDB.get_all_as_keyword() + + if configs == [] do + errors( + conn, + {:error, "To use configuration from database migrate your settings to database."} + ) + else + merged = + Pleroma.Config.Holder.config() + |> DeepMerge.deep_merge(configs) + |> Enum.map(fn {group, value} -> + Enum.map(value, fn {key, value} -> + db = + if configs[group][key] do + if Keyword.keyword?(value) do + Keyword.keys(value) |> Enum.map(fn key -> ConfigDB.convert(key) end) + else + ConfigDB.convert(key) + end + end + + setting = %{ + group: ConfigDB.convert(group), + key: ConfigDB.convert(key), + value: ConfigDB.convert(value) + } + + if db, do: Map.put(setting, :db, db), else: setting + end) + end) + |> List.flatten() + + json(conn, %{configs: merged}) + end + end + end + def config_update(conn, %{"configs" => configs}) do with :ok <- configurable_from_database(conn) do updated = diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8cd7e021a..ef6e5a565 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -196,7 +196,6 @@ defmodule Pleroma.Web.Router do get("/config", AdminAPIController, :config_show) post("/config", AdminAPIController, :config_update) get("/config/descriptions", AdminAPIController, :config_descriptions) - get("/config/migrate_to_db", AdminAPIController, :migrate_to_db) get("/config/migrate_from_db", AdminAPIController, :migrate_from_db) get("/moderation_log", AdminAPIController, :list_log) -- cgit v1.2.3 From 58e8963824bd3375ec1fa04b265187a888aaa5ea Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 Jan 2020 11:54:22 +0300 Subject: fix for config loader --- lib/pleroma/config/holder.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex index aa35382b2..c8badc52c 100644 --- a/lib/pleroma/config/holder.ex +++ b/lib/pleroma/config/holder.ex @@ -12,8 +12,8 @@ defmodule Pleroma.Config.Loader do # support for Elixir less than 1.9 @spec load() :: map() def load do - config = Mix.Config.eval!("config/config.exs") - env_config = Mix.Config.eval!("config/#{Mix.env()}.exs") + {config, _paths} = Mix.Config.eval!("config/config.exs") + {env_config, _paths} = Mix.Config.eval!("config/#{Mix.env()}.exs") Mix.Config.merge(config, env_config) end -- cgit v1.2.3 From b310feeccb03a9bc232b49d93fb03805e3d5c2d8 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 Jan 2020 15:00:20 +0300 Subject: compile fix --- lib/mix/tasks/pleroma/config.ex | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 3157e7b20..d2abbd885 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -68,12 +68,15 @@ defmodule Mix.Tasks.Pleroma.Config do end end + if Code.ensure_loaded?(Config.Reader) do + defp read_file(config_file), do: Config.Reader.read_imports!(config_file) + else + defp read_file(config_file), do: Mix.Config.eval!(config_file) + end + defp do_migrate_to_db(config_file) do if File.exists?(config_file) do - {custom_config, _paths} = - if Code.ensure_loaded?(Config.Reader), - do: Config.Reader.read_imports!(config_file), - else: Mix.Config.eval!(config_file) + {custom_config, _paths} = read_file(config_file) custom_config |> Keyword.keys() -- cgit v1.2.3 From 108a39c8766402dcbd0235d8746e2100a18e5813 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 17 Jan 2020 14:55:36 +0300 Subject: updated error messages for authentication process --- lib/pleroma/plugs/user_enabled_plug.ex | 8 +-- lib/pleroma/user.ex | 24 +++++-- lib/pleroma/web/oauth/oauth_controller.ex | 103 +++++++++++++++++++----------- 3 files changed, 84 insertions(+), 51 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex index 8d102ee5b..7b304eebc 100644 --- a/lib/pleroma/plugs/user_enabled_plug.ex +++ b/lib/pleroma/plugs/user_enabled_plug.ex @@ -11,11 +11,9 @@ defmodule Pleroma.Plugs.UserEnabledPlug do end def call(%{assigns: %{user: %User{} = user}} = conn, _) do - if User.auth_active?(user) do - conn - else - conn - |> assign(:user, nil) + case User.account_status(user) do + :active -> conn + _ -> assign(conn, :user, nil) end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 430f04ae9..3899c34c2 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -12,6 +12,7 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Ecto.Multi alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Conversation.Participation alias Pleroma.Delivery alias Pleroma.FollowingRelationship @@ -35,7 +36,7 @@ defmodule Pleroma.User do require Logger @type t :: %__MODULE__{} - + @type account_status :: :active | :deactivated | :password_reset_pending | :confirmation_pending @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength @@ -216,14 +217,21 @@ defmodule Pleroma.User do end end - @doc "Returns if the user should be allowed to authenticate" - def auth_active?(%User{deactivated: true}), do: false + @doc "Returns status account" + @spec account_status(User.t()) :: account_status() + def account_status(%User{deactivated: true}), do: :deactivated + def account_status(%User{password_reset_pending: true}), do: :password_reset_pending - def auth_active?(%User{confirmation_pending: true}), - do: !Pleroma.Config.get([:instance, :account_activation_required]) + def account_status(%User{confirmation_pending: true}) do + case Config.get([:instance, :account_activation_required]) do + true -> :confirmation_pending + _ -> :active + end + end - def auth_active?(%User{}), do: true + def account_status(%User{}), do: :active + @spec visible_for?(User.t(), User.t() | nil) :: boolean() def visible_for?(user, for_user \\ nil) def visible_for?(%User{invisible: true}, _), do: false @@ -231,15 +239,17 @@ defmodule Pleroma.User do def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true def visible_for?(%User{} = user, for_user) do - auth_active?(user) || superuser?(for_user) + account_status(user) == :active || superuser?(for_user) end def visible_for?(_, _), do: false + @spec superuser?(User.t()) :: boolean() def superuser?(%User{local: true, is_admin: true}), do: true def superuser?(%User{local: true, is_moderator: true}), do: true def superuser?(_), do: false + @spec invisible?(User.t()) :: boolean() def invisible?(%User{invisible: true}), do: true def invisible?(_), do: false diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index d31a3d91c..d5c0d97c0 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -167,17 +167,37 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp handle_create_authorization_error( %Plug.Conn{} = conn, - {:auth_active, false}, + {:account_status, :confirmation_pending}, %{"authorization" => _} = params ) do - # Per https://github.com/tootsuite/mastodon/blob/ - # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 conn |> put_flash(:error, dgettext("errors", "Your login is missing a confirmed e-mail address")) |> put_status(:forbidden) |> authorize(params) end + defp handle_create_authorization_error( + %Plug.Conn{} = conn, + {:account_status, :password_reset_pending}, + %{"authorization" => _} = params + ) do + conn + |> put_flash(:error, dgettext("errors", "Password reset is required")) + |> put_status(:forbidden) + |> authorize(params) + end + + defp handle_create_authorization_error( + %Plug.Conn{} = conn, + {:account_status, :deactivated}, + %{"authorization" => _} = params + ) do + conn + |> put_flash(:error, dgettext("errors", "Your account is currently disabled")) + |> put_status(:forbidden) + |> authorize(params) + end + defp handle_create_authorization_error(%Plug.Conn{} = conn, error, %{"authorization" => _}) do Authenticator.handle_error(conn, error) end @@ -218,46 +238,14 @@ defmodule Pleroma.Web.OAuth.OAuthController do ) do with {:ok, %User{} = user} <- Authenticator.get_user(conn), {:ok, app} <- Token.Utils.fetch_app(conn), - {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, - {:user_active, true} <- {:user_active, !user.deactivated}, - {:password_reset_pending, false} <- - {:password_reset_pending, user.password_reset_pending}, + {:account_status, :active} <- {:account_status, User.account_status(user)}, {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do json(conn, Token.Response.build(user, token)) else - {:auth_active, false} -> - # Per https://github.com/tootsuite/mastodon/blob/ - # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 - render_error( - conn, - :forbidden, - "Your login is missing a confirmed e-mail address", - %{}, - "missing_confirmed_email" - ) - - {:user_active, false} -> - render_error( - conn, - :forbidden, - "Your account is currently disabled", - %{}, - "account_is_disabled" - ) - - {:password_reset_pending, true} -> - render_error( - conn, - :forbidden, - "Password reset is required", - %{}, - "password_reset_required" - ) - - _error -> - render_invalid_credentials_error(conn) + error -> + handle_token_exchange_error(conn, error) end end @@ -286,6 +274,43 @@ defmodule Pleroma.Web.OAuth.OAuthController do # Bad request def token_exchange(%Plug.Conn{} = conn, params), do: bad_request(conn, params) + defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :deactivated}) do + render_error( + conn, + :forbidden, + "Your account is currently disabled", + %{}, + "account_is_disabled" + ) + end + + defp handle_token_exchange_error( + %Plug.Conn{} = conn, + {:account_status, :password_reset_pending} + ) do + render_error( + conn, + :forbidden, + "Password reset is required", + %{}, + "password_reset_required" + ) + end + + defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :confirmation_pending}) do + render_error( + conn, + :forbidden, + "Your login is missing a confirmed e-mail address", + %{}, + "missing_confirmed_email" + ) + end + + defp handle_token_exchange_error(%Plug.Conn{} = conn, _error) do + render_invalid_credentials_error(conn) + end + def token_revoke(%Plug.Conn{} = conn, %{"token" => _token} = params) do with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, _token} <- RevokeToken.revoke(app, params) do @@ -472,7 +497,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do %App{} = app <- Repo.get_by(App, client_id: client_id), true <- redirect_uri in String.split(app.redirect_uris), {:ok, scopes} <- validate_scopes(app, auth_attrs), - {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do + {:account_status, :active} <- {:account_status, User.account_status(user)} do Authorization.create_authorization(app, user, scopes) end end -- cgit v1.2.3 From 9e10b90b5bdf0f1ae327a44f44187918ab8dbf4f Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 Jan 2020 15:06:42 +0300 Subject: configure only console backend --- lib/mix/pleroma.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index ea9923440..a6b00d4be 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -9,7 +9,7 @@ defmodule Mix.Pleroma do if Pleroma.Config.get(:env) != :test and change_logger_level do require Logger - Logger.configure(level: :debug) + Logger.configure(:console, level: :debug) end {:ok, _} = Application.ensure_all_started(:pleroma) -- cgit v1.2.3 From ce027fd0ef1080b03e7982e5939b0c7db6e3b783 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 Jan 2020 15:13:24 +0300 Subject: revert non needable --- lib/mix/pleroma.ex | 7 +++---- lib/mix/tasks/pleroma/config.ex | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index a6b00d4be..73a076a53 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -4,12 +4,11 @@ defmodule Mix.Pleroma do @doc "Common functions to be reused in mix tasks" - def start_pleroma(change_logger_level \\ true) do + def start_pleroma do Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) - if Pleroma.Config.get(:env) != :test and change_logger_level do - require Logger - Logger.configure(:console, level: :debug) + if Pleroma.Config.get(:env) != :test do + Application.put_env(:logger, :console, level: :debug) end {:ok, _} = Application.ensure_all_started(:pleroma) diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index d2abbd885..43039ae77 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -17,7 +17,7 @@ defmodule Mix.Tasks.Pleroma.Config do def run(["migrate_to_db"]) do # we want to save original logger level - start_pleroma(false) + start_pleroma() migrate_to_db() end -- cgit v1.2.3 From 7676ed82397d73a20aad1ae4b47690923ddfb162 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 Jan 2020 16:28:44 +0300 Subject: some clean up --- lib/mix/tasks/pleroma/config.ex | 1 - lib/mix/tasks/pleroma/docs.ex | 2 +- lib/pleroma/config/config_db.ex | 17 +++++------------ lib/pleroma/config/holder.ex | 17 +++++++++++++---- lib/pleroma/config/transfer_task.ex | 15 ++++++++++++++- lib/pleroma/docs/json.ex | 2 +- 6 files changed, 34 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 43039ae77..148d18141 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -16,7 +16,6 @@ defmodule Mix.Tasks.Pleroma.Config do @moduledoc File.read!("docs/administration/CLI_tasks/config.md") def run(["migrate_to_db"]) do - # we want to save original logger level start_pleroma() migrate_to_db() end diff --git a/lib/mix/tasks/pleroma/docs.ex b/lib/mix/tasks/pleroma/docs.ex index 0d2663648..3c870f876 100644 --- a/lib/mix/tasks/pleroma/docs.ex +++ b/lib/mix/tasks/pleroma/docs.ex @@ -28,7 +28,7 @@ defmodule Mix.Tasks.Pleroma.Docs do defp do_run(implementation) do start_pleroma() - with {descriptions, _paths} <- Mix.Config.eval!("config/description.exs"), + with descriptions <- Pleroma.Config.Loader.load("config/description.exs"), {:ok, file_path} <- Pleroma.Docs.Generator.process( implementation, diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 294fbc3f0..6d48e0300 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -192,7 +192,6 @@ defmodule Pleroma.ConfigDB do } end - defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]} # TODO: will become useless after removing hackney defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]} @@ -229,14 +228,13 @@ defmodule Pleroma.ConfigDB do {:proxy_url, {do_transform_string(type), parse_host(host), port}} end - defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do - {dispatch_settings, []} = do_eval(entity) - {:dispatch, [dispatch_settings]} - end - # TODO: will become useless after removing hackney defp do_transform(%{"tuple" => [":partial_chain", entity]}) do - {partial_chain, []} = do_eval(entity) + {partial_chain, []} = + entity + |> String.replace(~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "") + |> Code.eval_string() + {:partial_chain, partial_chain} end @@ -322,9 +320,4 @@ defmodule Pleroma.ConfigDB do Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack)\./, string) or string in ["Oban", "Ueberauth", "ExSyslogger"] end - - defp do_eval(entity) do - cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "") - Code.eval_string(cleaned_string) - end end diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex index c8badc52c..0d9cfef66 100644 --- a/lib/pleroma/config/holder.ex +++ b/lib/pleroma/config/holder.ex @@ -3,20 +3,29 @@ defmodule Pleroma.Config.Loader do if Code.ensure_loaded?(Config.Reader) do @spec load() :: map() def load do - config = Config.Reader.read!("config/config.exs") - env_config = Config.Reader.read!("config/#{Mix.env()}.exs") + config = load("config/config.exs") + env_config = load("config/#{Mix.env()}.exs") Config.Reader.merge(config, env_config) end + + @spec load(Path.t()) :: keyword() + def load(path), do: Config.Reader.read!(path) else # support for Elixir less than 1.9 @spec load() :: map() def load do - {config, _paths} = Mix.Config.eval!("config/config.exs") - {env_config, _paths} = Mix.Config.eval!("config/#{Mix.env()}.exs") + {config, _paths} = load("config/config.exs") + {env_config, _paths} = load("config/#{Mix.env()}.exs") Mix.Config.merge(config, env_config) end + + @spec load(Path.t()) :: keyword() + def load(path) do + {config, _paths} = Mix.Config.eval!(path) + config + end end end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 828a297de..70b51cb4d 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -48,7 +48,20 @@ defmodule Pleroma.Config.TransferTask do end :ok = Application.put_env(group, key, merged_value) - group + + if group != :logger do + group + else + # change logger configuration in runtime, without restart + if Keyword.keyword?(merged_value) and + key not in [:compile_time_application, :backends, :compile_time_purge_matching] do + Logger.configure_backend(key, merged_value) + else + Logger.configure([{key, merged_value}]) + end + + nil + end end rescue e -> diff --git a/lib/pleroma/docs/json.ex b/lib/pleroma/docs/json.ex index f191b6013..6508a7bdb 100644 --- a/lib/pleroma/docs/json.ex +++ b/lib/pleroma/docs/json.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Docs.JSON do end def compile do - with {config, _paths} <- Mix.Config.eval!("config/description.exs") do + with config <- Pleroma.Config.Loader.load("config/description.exs") do config[:pleroma][:config_description] |> Pleroma.Docs.Generator.convert_to_strings() |> Jason.encode!() -- cgit v1.2.3 From 89e93fb33f6295428dd84a50c9ca44e26bd169c3 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 Jan 2020 18:08:45 +0300 Subject: return db key on update requests --- lib/pleroma/config/config_db.ex | 19 ++++++++++++++++++- lib/pleroma/config/holder.ex | 4 ++-- lib/pleroma/config/transfer_task.ex | 4 +++- lib/pleroma/web/admin_api/admin_api_controller.ex | 13 ++++++------- lib/pleroma/web/admin_api/views/config_view.ex | 8 +++++++- 5 files changed, 36 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 6d48e0300..93b02370c 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -16,6 +16,7 @@ defmodule Pleroma.ConfigDB do field(:key, :string) field(:group, :string) field(:value, :binary) + field(:db, {:array, :string}, virtual: true, default: []) timestamps() end @@ -61,6 +62,22 @@ defmodule Pleroma.ConfigDB do |> Repo.update() end + @spec get_db_keys(ConfigDB.t()) :: [String.t()] + def get_db_keys(%ConfigDB{} = config) do + config.value + |> ConfigDB.from_binary() + |> get_db_keys(config.key) + end + + @spec get_db_keys(keyword() | any()) :: [String.t()] + def get_db_keys(value, key) do + if Keyword.keyword?(value) do + value |> Keyword.keys() |> Enum.map(&convert(&1)) + else + [convert(key)] + end + end + @full_key_update [ {:pleroma, :ecto_repos}, {:pleroma, :assets}, @@ -317,7 +334,7 @@ defmodule Pleroma.ConfigDB do @spec is_module_name?(String.t()) :: boolean() def is_module_name?(string) do - Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack)\./, string) or + Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth)\./, string) or string in ["Oban", "Ueberauth", "ExSyslogger"] end end diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex index 0d9cfef66..7436df1a7 100644 --- a/lib/pleroma/config/holder.ex +++ b/lib/pleroma/config/holder.ex @@ -15,8 +15,8 @@ defmodule Pleroma.Config.Loader do # support for Elixir less than 1.9 @spec load() :: map() def load do - {config, _paths} = load("config/config.exs") - {env_config, _paths} = load("config/#{Mix.env()}.exs") + config = load("config/config.exs") + env_config = load("config/#{Mix.env()}.exs") Mix.Config.merge(config, env_config) end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 70b51cb4d..6e651c48b 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -66,7 +66,9 @@ defmodule Pleroma.Config.TransferTask do rescue e -> Logger.warn( - "updating env causes error, key: #{inspect(setting.key)}, error: #{inspect(e)}" + "updating env causes error, group: #{inspect(setting.group)}, key: #{ + inspect(setting.key) + }, value: #{inspect(ConfigDB.from_binary(setting.value))}, error: #{inspect(e)}" ) nil diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index cc93c2309..7572a6b65 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -827,15 +827,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do merged = Pleroma.Config.Holder.config() |> DeepMerge.deep_merge(configs) - |> Enum.map(fn {group, value} -> - Enum.map(value, fn {key, value} -> + |> Enum.map(fn {group, values} -> + Enum.map(values, fn {key, value} -> db = if configs[group][key] do - if Keyword.keyword?(value) do - Keyword.keys(value) |> Enum.map(fn key -> ConfigDB.convert(key) end) - else - ConfigDB.convert(key) - end + ConfigDB.get_db_keys(value, key) end setting = %{ @@ -871,6 +867,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end) |> Enum.reject(&is_nil(&1)) + |> Enum.map(fn config -> + Map.put(config, :db, ConfigDB.get_db_keys(config)) + end) Pleroma.Config.TransferTask.load_and_update_env() diff --git a/lib/pleroma/web/admin_api/views/config_view.ex b/lib/pleroma/web/admin_api/views/config_view.ex index 72b042ab7..23d97e847 100644 --- a/lib/pleroma/web/admin_api/views/config_view.ex +++ b/lib/pleroma/web/admin_api/views/config_view.ex @@ -12,10 +12,16 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do end def render("show.json", %{config: config}) do - %{ + map = %{ key: config.key, group: config.group, value: Pleroma.ConfigDB.from_binary_with_convert(config.value) } + + if config.db != [] do + Map.put(map, :db, config.db) + else + map + end end end -- cgit v1.2.3 From 81133702d4246e5e5c17ea4d4119747dc880edd6 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 17 Jan 2020 20:20:37 +0300 Subject: Delete attachments after object and cache cleanup --- lib/pleroma/object.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 6c56a9c62..499339982 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -180,10 +180,10 @@ defmodule Pleroma.Object do def delete(%Object{data: %{"id" => id}} = object) do with {:ok, _obj} = swap_object_with_tombstone(object), - :ok <- delete_attachments(object), deleted_activity = Activity.delete_all_by_object_ap_id(id), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), - {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do + {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path), + :ok <- delete_attachments(object) do {:ok, object, deleted_activity} end end -- cgit v1.2.3 From e69986169095796f2845c4f859234d96f91bf9ff Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Sat, 18 Jan 2020 12:25:56 +0300 Subject: full update for some subkeys --- lib/pleroma/config/config_db.ex | 65 +++++++++++++++++++++-- lib/pleroma/config/transfer_task.ex | 2 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 12 ++++- 3 files changed, 73 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 93b02370c..85a049f8a 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -69,7 +69,7 @@ defmodule Pleroma.ConfigDB do |> get_db_keys(config.key) end - @spec get_db_keys(keyword() | any()) :: [String.t()] + @spec get_db_keys(keyword(), any()) :: [String.t()] def get_db_keys(value, key) do if Keyword.keyword?(value) do value |> Keyword.keys() |> Enum.map(&convert(&1)) @@ -78,9 +78,57 @@ defmodule Pleroma.ConfigDB do end end + @full_subkey_update [ + {:pleroma, :assets, :mascots}, + {:pleroma, :emoji, :groups}, + {:pleroma, :workers, :retries}, + {:pleroma, :mrf_subchain, :match_actor}, + {:pleroma, :mrf_keyword, :replace} + ] + + @spec deep_merge(atom(), atom(), keyword(), keyword()) :: keyword() + def deep_merge(group, key, old_value, new_value) do + old_keys = + old_value + |> Keyword.keys() + |> MapSet.new() + + new_keys = + new_value + |> Keyword.keys() + |> MapSet.new() + + intersect_keys = old_keys |> MapSet.intersection(new_keys) |> MapSet.to_list() + + subkeys = sub_key_full_update(group, key, intersect_keys) + + merged_value = DeepMerge.deep_merge(old_value, new_value) + + Enum.reduce(subkeys, merged_value, fn subkey, acc -> + Keyword.put(acc, subkey, new_value[subkey]) + end) + end + + @spec sub_key_full_update?(atom(), atom(), [Keyword.key()]) :: boolean() + def sub_key_full_update?(group, key, subkeys) do + Enum.any?(@full_subkey_update, fn {g, k, subkey} -> + g == group and k == key and subkey in subkeys + end) + end + + defp sub_key_full_update(group, key, subkeys) do + Enum.map(@full_subkey_update, fn + {g, k, subkey} when g == group and k == key -> + if subkey in subkeys, do: subkey, else: [] + + _ -> + [] + end) + |> List.flatten() + end + @full_key_update [ {:pleroma, :ecto_repos}, - {:pleroma, :assets}, {:quack, :meta}, {:mime, :types}, {:cors_plug, [:max_age, :methods, :expose, :headers]}, @@ -114,8 +162,14 @@ defmodule Pleroma.ConfigDB do old_value <- from_binary(config.value), transformed_value <- do_transform(params[:value]), {:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config}, - new_value <- DeepMerge.deep_merge(old_value, transformed_value) do - ConfigDB.update(config, %{value: new_value, transformed?: true}) + new_value <- + deep_merge( + ConfigDB.from_string(config.group), + ConfigDB.from_string(config.key), + old_value, + transformed_value + ) do + ConfigDB.update(config, %{value: new_value}) else {reason, false, config} when reason in [:partial_update, :can_be_merged] -> ConfigDB.update(config, params) @@ -236,6 +290,9 @@ defmodule Pleroma.ConfigDB do def transform(entity), do: to_binary(entity) + @spec transform_with_out_binary(any()) :: any() + def transform_with_out_binary(entity), do: do_transform(entity) + @spec to_binary(any()) :: binary() def to_binary(entity), do: :erlang.term_to_binary(entity) diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 6e651c48b..9b571d5d9 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -42,7 +42,7 @@ defmodule Pleroma.Config.TransferTask do merged_value = if can_be_merged?(default, value) do - DeepMerge.deep_merge(default, value) + ConfigDB.deep_merge(group, key, default, value) else value end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 7572a6b65..cc658dc0e 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -834,10 +834,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ConfigDB.get_db_keys(value, key) end + db_value = configs[group][key] + + merged_value = + if !is_nil(db_value) and Keyword.keyword?(db_value) and + ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do + ConfigDB.deep_merge(group, key, value, db_value) + else + value + end + setting = %{ group: ConfigDB.convert(group), key: ConfigDB.convert(key), - value: ConfigDB.convert(value) + value: ConfigDB.convert(merged_value) } if db, do: Map.put(setting, :db, db), else: setting -- cgit v1.2.3 From efb8ef5abee1a8defa2bfba40ad1065db4c09ddf Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Sat, 18 Jan 2020 16:55:33 +0300 Subject: releases support --- lib/mix/tasks/pleroma/config.ex | 49 +++++++++++++++++++++++++++-------------- lib/pleroma/config/holder.ex | 33 +-------------------------- lib/pleroma/config/loader.ex | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 48 deletions(-) create mode 100644 lib/pleroma/config/loader.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 148d18141..715b72dbe 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -10,8 +10,6 @@ defmodule Mix.Tasks.Pleroma.Config do alias Pleroma.ConfigDB alias Pleroma.Repo - require Logger - @shortdoc "Manages the location of the config" @moduledoc File.read!("docs/administration/CLI_tasks/config.md") @@ -32,10 +30,10 @@ defmodule Mix.Tasks.Pleroma.Config do with {:active?, true} <- {:active?, Pleroma.Config.get([:configurable_from_database])}, - env_path when is_binary(env_path) <- opts[:env], - config_path <- "config/#{env_path}.exported_from_db.secret.exs", + env when is_binary(env) <- opts[:env] || "prod", + config_path <- config_path(env), {:ok, file} <- File.open(config_path, [:write, :utf8]) do - IO.write(file, "use Mix.Config\r\n") + IO.write(file, config_header()) ConfigDB |> Repo.all() @@ -45,31 +43,50 @@ defmodule Mix.Tasks.Pleroma.Config do System.cmd("mix", ["format", config_path]) else {:active?, false} -> - Mix.shell().info( - "migration is not allowed by config. You can change this behavior in instance settings." + shell_info( + "Migration is not allowed by config. You can change this behavior in instance settings." ) error -> - Mix.shell().info("error occuried while opening file. #{inspect(error)}") + shell_info("Error occuried while opening file. #{inspect(error)}") end end + defp config_path(env) do + path = + if Pleroma.Config.get(:release) do + :config_path + |> Pleroma.Config.get() + |> Path.dirname() + else + "config" + end + + Path.join(path, "#{env}.exported_from_db.secret.exs") + end + @spec migrate_to_db(Path.t() | nil) :: any() def migrate_to_db(file_path \\ nil) do if Pleroma.Config.get([:configurable_from_database]) do - # TODO: add support for releases - config_file = file_path || "config/#{Pleroma.Config.get(:env)}.secret.exs" + user_config_file = + if Pleroma.Config.get(:release), + do: Pleroma.Config.get(:config_path), + else: "config/#{Pleroma.Config.get(:env)}.secret.exs" + + config_file = file_path || user_config_file do_migrate_to_db(config_file) else - Mix.shell().info( - "migration is not allowed by config. You can change this behavior in instance settings." + shell_info( + "Migration is not allowed by config. You can change this behavior in instance settings." ) end end if Code.ensure_loaded?(Config.Reader) do + defp config_header, do: "import Config\r\n\r\n" defp read_file(config_file), do: Config.Reader.read_imports!(config_file) else + defp config_header, do: "use Mix.Config\r\n\r\n" defp read_file(config_file), do: Mix.Config.eval!(config_file) end @@ -81,7 +98,7 @@ defmodule Mix.Tasks.Pleroma.Config do |> Keyword.keys() |> Enum.each(&create(&1, custom_config[&1])) else - Logger.warn("to migrate settings, you must define custom settings in #{config_file}") + shell_info("To migrate settings, you must define custom settings in #{config_file}.") end end @@ -94,10 +111,10 @@ defmodule Mix.Tasks.Pleroma.Config do key = inspect(key) {:ok, _} = ConfigDB.update_or_create(%{group: inspect(group), key: key, value: value}) - Mix.shell().info("settings for key #{key} migrated.") + shell_info("Settings for key #{key} migrated.") end) - Mix.shell().info("settings for group :#{group} migrated.") + shell_info("Settings for group :#{group} migrated.") end defp write_to_file_with_deletion(config, file, with_deletion) do @@ -110,7 +127,7 @@ defmodule Mix.Tasks.Pleroma.Config do if with_deletion do {:ok, _} = Repo.delete(config) - Mix.shell().info("#{config.key} deleted from DB.") + shell_info("#{config.key} deleted from DB.") end end end diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex index 7436df1a7..0fa7c5bf7 100644 --- a/lib/pleroma/config/holder.ex +++ b/lib/pleroma/config/holder.ex @@ -1,36 +1,5 @@ -defmodule Pleroma.Config.Loader do - # TODO: add support for releases - if Code.ensure_loaded?(Config.Reader) do - @spec load() :: map() - def load do - config = load("config/config.exs") - env_config = load("config/#{Mix.env()}.exs") - - Config.Reader.merge(config, env_config) - end - - @spec load(Path.t()) :: keyword() - def load(path), do: Config.Reader.read!(path) - else - # support for Elixir less than 1.9 - @spec load() :: map() - def load do - config = load("config/config.exs") - env_config = load("config/#{Mix.env()}.exs") - - Mix.Config.merge(config, env_config) - end - - @spec load(Path.t()) :: keyword() - def load(path) do - {config, _paths} = Mix.Config.eval!(path) - config - end - end -end - defmodule Pleroma.Config.Holder do - @config Pleroma.Config.Loader.load() + @config Pleroma.Config.Loader.load_and_merge() @spec config() :: keyword() def config do diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex new file mode 100644 index 000000000..b13b6eaf4 --- /dev/null +++ b/lib/pleroma/config/loader.ex @@ -0,0 +1,39 @@ +defmodule Pleroma.Config.Loader do + @paths ["config/config.exs", "config/#{Mix.env()}.exs"] + + if Code.ensure_loaded?(Config.Reader) do + @spec load(Path.t()) :: keyword() + def load(path), do: Config.Reader.read!(path) + + defp do_merge(conf1, conf2), do: Config.Reader.merge(conf1, conf2) + else + # support for Elixir less than 1.9 + @spec load(Path.t()) :: keyword() + def load(path) do + {config, _paths} = Mix.Config.eval!(path) + config + end + + defp do_merge(conf1, conf2), do: Mix.Config.merge(conf1, conf2) + end + + @spec load_and_merge() :: keyword() + def load_and_merge do + all_paths = + if Pleroma.Config.get(:release), + do: @paths ++ ["config/releases.exs"], + else: @paths + + all_paths + |> Enum.map(&load(&1)) + |> merge() + end + + @spec merge([keyword()], keyword()) :: keyword() + def merge(configs, acc \\ []) + def merge([], acc), do: acc + + def merge([config | others], acc) do + merge(others, do_merge(acc, config)) + end +end -- cgit v1.2.3 From 6cf3b19a38d08b37a686cd1059604816d11708f1 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 19 Jan 2020 07:02:16 +0100 Subject: transmogrifier.ex: simplify handle_incoming of actors --- lib/pleroma/web/activity_pub/transmogrifier.ex | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 3fa789d53..2b8bfc3bd 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -658,24 +658,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) - locked = new_user_data[:locked] || false - attachment = get_in(new_user_data, [:source_data, "attachment"]) || [] - invisible = new_user_data[:invisible] || false - - fields = - attachment - |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) - |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) - - update_data = - new_user_data - |> Map.take([:avatar, :banner, :bio, :name, :also_known_as]) - |> Map.put(:fields, fields) - |> Map.put(:locked, locked) - |> Map.put(:invisible, invisible) - actor - |> User.upgrade_changeset(update_data, true) + |> User.upgrade_changeset(new_user_data, true) |> User.update_and_set_cache() ActivityPub.update(%{ -- cgit v1.2.3 From d6a532bf0f280cc191a9f2c1f53af31c451481d9 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 19 Jan 2020 19:45:20 +0300 Subject: Delete attachments asynchronously --- lib/pleroma/object.ex | 79 ++------------------ lib/pleroma/workers/attachments_cleanup_worker.ex | 87 +++++++++++++++++++++++ 2 files changed, 93 insertions(+), 73 deletions(-) create mode 100644 lib/pleroma/workers/attachments_cleanup_worker.ex (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 499339982..38e372f6d 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -19,6 +19,8 @@ defmodule Pleroma.Object do @type t() :: %__MODULE__{} + @derive {Jason.Encoder, only: [:data]} + schema "objects" do field(:data, :map) @@ -183,83 +185,14 @@ defmodule Pleroma.Object do deleted_activity = Activity.delete_all_by_object_ap_id(id), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path), - :ok <- delete_attachments(object) do + {:ok, _} <- + Pleroma.Workers.AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{ + "object" => object + }) do {:ok, object, deleted_activity} end end - defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" => actor}}) do - hrefs = - Enum.flat_map(attachments, fn attachment -> - Enum.map(attachment["url"], & &1["href"]) - end) - - names = Enum.map(attachments, & &1["name"]) - - uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) - - # find all objects for copies of the attachments, name and actor doesn't matter here - delete_ids = - from(o in Object, - where: - fragment( - "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)", - o.data, - o.data, - ^hrefs - ) - ) - |> Repo.all() - # we should delete 1 object for any given attachment, but don't delete files if - # there are more than 1 object for it - |> Enum.reduce(%{}, fn %{ - id: id, - data: %{ - "url" => [%{"href" => href}], - "actor" => obj_actor, - "name" => name - } - }, - acc -> - Map.update(acc, href, %{id: id, count: 1}, fn val -> - case obj_actor == actor and name in names do - true -> - # set id of the actor's object that will be deleted - %{val | id: id, count: val.count + 1} - - false -> - # another actor's object, just increase count to not delete file - %{val | count: val.count + 1} - end - end) - end) - |> Enum.map(fn {href, %{id: id, count: count}} -> - # only delete files that have single instance - with 1 <- count do - prefix = - case Pleroma.Config.get([Pleroma.Upload, :base_url]) do - nil -> "media" - _ -> "" - end - - base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url()) - - file_path = String.trim_leading(href, "#{base_url}/#{prefix}") - - uploader.delete_file(file_path) - end - - id - end) - - from(o in Object, where: o.id in ^delete_ids) - |> Repo.delete_all() - - :ok - end - - defp delete_attachments(%{data: _data}), do: :ok - def prune(%Object{data: %{"id" => id}} = object) do with {:ok, object} <- Repo.delete(object), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex new file mode 100644 index 000000000..f8239ece6 --- /dev/null +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -0,0 +1,87 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.AttachmentsCleanupWorker do + import Ecto.Query + + alias Pleroma.Object + alias Pleroma.Repo + + use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup" + + @impl Oban.Worker + def perform( + %{"object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}}}, + _job + ) do + hrefs = + Enum.flat_map(attachments, fn attachment -> + Enum.map(attachment["url"], & &1["href"]) + end) + + names = Enum.map(attachments, & &1["name"]) + + uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) + + # find all objects for copies of the attachments, name and actor doesn't matter here + delete_ids = + from(o in Object, + where: + fragment( + "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)", + o.data, + o.data, + ^hrefs + ) + ) + # The query above can be time consumptive on large instances until we refactor how uploads are stored + |> Repo.all(timout: :infinity) + # we should delete 1 object for any given attachment, but don't delete files if + # there are more than 1 object for it + |> Enum.reduce(%{}, fn %{ + id: id, + data: %{ + "url" => [%{"href" => href}], + "actor" => obj_actor, + "name" => name + } + }, + acc -> + Map.update(acc, href, %{id: id, count: 1}, fn val -> + case obj_actor == actor and name in names do + true -> + # set id of the actor's object that will be deleted + %{val | id: id, count: val.count + 1} + + false -> + # another actor's object, just increase count to not delete file + %{val | count: val.count + 1} + end + end) + end) + |> Enum.map(fn {href, %{id: id, count: count}} -> + # only delete files that have single instance + with 1 <- count do + prefix = + case Pleroma.Config.get([Pleroma.Upload, :base_url]) do + nil -> "media" + _ -> "" + end + + base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url()) + + file_path = String.trim_leading(href, "#{base_url}/#{prefix}") + + uploader.delete_file(file_path) + end + + id + end) + + from(o in Object, where: o.id in ^delete_ids) + |> Repo.delete_all() + end + + def perform(%{"object" => _object}, _job), do: :ok +end -- cgit v1.2.3 From cde828ff7df64740f36b2fc9dfdbfc8d76a8a78d Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 19 Jan 2020 22:09:47 +0300 Subject: Fix credo warning --- lib/pleroma/workers/attachments_cleanup_worker.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index f8239ece6..3f421db40 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -35,10 +35,11 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do ^hrefs ) ) - # The query above can be time consumptive on large instances until we refactor how uploads are stored + # The query above can be time consumptive on large instances until we + # refactor how uploads are stored |> Repo.all(timout: :infinity) - # we should delete 1 object for any given attachment, but don't delete files if - # there are more than 1 object for it + # we should delete 1 object for any given attachment, but don't delete + # files if there are more than 1 object for it |> Enum.reduce(%{}, fn %{ id: id, data: %{ -- cgit v1.2.3 From dc0498ab2b7cee930f426e37ed4f167c2dc83262 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 16 Jan 2020 19:01:31 +0300 Subject: Check for unapplied migrations on startup Closes #1328 --- lib/pleroma/application.ex | 1 + lib/pleroma/repo.ex | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 2ae052069..e17068876 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -33,6 +33,7 @@ defmodule Pleroma.Application do def start(_type, _args) do Pleroma.HTML.compile_scrubbers() Pleroma.Config.DeprecationWarnings.warn() + Pleroma.Repo.check_migrations_applied!() setup_instrumenters() load_custom_modules() diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex index f57e088bc..cb0b6653c 100644 --- a/lib/pleroma/repo.ex +++ b/lib/pleroma/repo.ex @@ -8,6 +8,8 @@ defmodule Pleroma.Repo do adapter: Ecto.Adapters.Postgres, migration_timestamps: [type: :naive_datetime_usec] + require Logger + defmodule Instrumenter do use Prometheus.EctoInstrumenter end @@ -47,4 +49,37 @@ defmodule Pleroma.Repo do _ -> {:error, :not_found} end end + + def check_migrations_applied!() do + unless Pleroma.Config.get( + [:i_am_aware_this_may_cause_data_loss, :disable_migration_check], + false + ) do + Ecto.Migrator.with_repo(__MODULE__, fn repo -> + down_migrations = + Ecto.Migrator.migrations(repo) + |> Enum.reject(fn + {:up, _, _} -> true + {:down, _, _} -> false + end) + + if length(down_migrations) > 0 do + down_migrations_text = + Enum.map(down_migrations, fn {:down, id, name} -> "- #{name} (#{id})\n" end) + + Logger.error( + "The following migrations were not applied:\n#{down_migrations_text}If you want to start Pleroma anyway, set\nconfig :pleroma, :i_am_aware_this_may_cause_data_loss, disable_migration_check: true" + ) + + raise Pleroma.Repo.UnappliedMigrationsError + end + end) + else + :ok + end + end +end + +defmodule Pleroma.Repo.UnappliedMigrationsError do + defexception message: "Unapplied Migrations detected" end -- cgit v1.2.3 From 5c533e10e73d92b753d9ac20b2d7ab14f42649b2 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 20 Jan 2020 11:53:14 +0100 Subject: Bump credo to 1.1.5 --- lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex | 2 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex | 2 +- lib/pleroma/web/oauth/oauth_controller.ex | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex index 4eaea00d8..c184c3b66 100644 --- a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]), rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]), true <- - length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type), + Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type), false <- length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type), {:ok, _} <- filter(message["object"]) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 529169c1b..78b77a97a 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -639,7 +639,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) - Enum.map(users, &User.force_password_reset_async/1) + Enum.each(users, &User.force_password_reset_async/1) ModerationLog.insert_log(%{ actor: admin, diff --git a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex index fc7d52824..11f7b85d3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex @@ -6,9 +6,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do @moduledoc "The module represents functions to manage user subscriptions." use Pleroma.Web, :controller + alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View alias Pleroma.Web.Push alias Pleroma.Web.Push.Subscription - alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View action_fallback(:errors) diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index d31a3d91c..5292aedf2 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -14,10 +14,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do alias Pleroma.Web.ControllerHelper alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization + alias Pleroma.Web.OAuth.Scopes alias Pleroma.Web.OAuth.Token alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken - alias Pleroma.Web.OAuth.Scopes require Logger -- cgit v1.2.3 From 5fddf988ea45382d8e2307f11205afcc4b468d45 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 13:05:35 +0100 Subject: Pleroma API: `emoji_reactions_by` does not need authorization --- lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 772c535a4..3285dc11b 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -23,7 +23,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do plug( OAuthScopesPlug, %{scopes: ["read:statuses"]} - when action in [:conversation, :conversation_statuses, :emoji_reactions_by] + when action in [:conversation, :conversation_statuses] ) plug( -- cgit v1.2.3 From 510776ba31f0bb01217fd6585848657f5bceb5f7 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 14:27:59 +0100 Subject: CommonAPI: Don't error out on double favs/repeats --- lib/pleroma/web/common_api/common_api.ex | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 2f3bcfc3c..c05a6c544 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -85,9 +85,13 @@ defmodule Pleroma.Web.CommonAPI do def repeat(id_or_ap_id, user, params \\ %{}) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), object <- Object.normalize(activity), - nil <- Utils.get_existing_announce(user.ap_id, object), + announce_activity <- Utils.get_existing_announce(user.ap_id, object), public <- public_announce?(object, params) do - ActivityPub.announce(user, object, nil, true, public) + if announce_activity do + {:ok, announce_activity, object} + else + ActivityPub.announce(user, object, nil, true, public) + end else _ -> {:error, dgettext("errors", "Could not repeat")} end @@ -105,8 +109,12 @@ defmodule Pleroma.Web.CommonAPI do def favorite(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), object <- Object.normalize(activity), - nil <- Utils.get_existing_like(user.ap_id, object) do - ActivityPub.like(user, object) + like_activity <- Utils.get_existing_like(user.ap_id, object) do + if like_activity do + {:ok, like_activity, object} + else + ActivityPub.like(user, object) + end else _ -> {:error, dgettext("errors", "Could not favorite")} end -- cgit v1.2.3 From 4c5b5f14dcec51cba8e86bcfcf2943ee9b49b0e4 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 16:24:20 +0100 Subject: StatusView: Add `emoji_reactions` --- lib/pleroma/web/mastodon_api/views/status_view.ex | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index e9590224b..b59ac39bc 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -253,6 +253,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do nil end + emoji_reactions = + with %{data: %{"reactions" => emoji_reactions}} <- object do + Enum.map(emoji_reactions, fn {emoji, users} -> + {emoji, length(users)} + end) + |> Enum.into(%{}) + else + _ -> %{} + end + %{ id: to_string(activity.id), uri: object.data["id"], @@ -293,7 +303,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do spoiler_text: %{"text/plain" => summary_plaintext}, expires_at: expires_at, direct_conversation_id: direct_conversation_id, - thread_muted: thread_muted? + thread_muted: thread_muted?, + emoji_reactions: emoji_reactions } } end -- cgit v1.2.3 From 8023fa48dbc68fe696337a4da940b95fd209e304 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Mon, 20 Jan 2020 18:25:00 +0300 Subject: merge fix --- lib/pleroma/config/config_db.ex | 20 +++++++++++++++++++- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 85a049f8a..0091f7a1b 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -102,7 +102,7 @@ defmodule Pleroma.ConfigDB do subkeys = sub_key_full_update(group, key, intersect_keys) - merged_value = DeepMerge.deep_merge(old_value, new_value) + merged_value = ConfigDB.merge(old_value, new_value) Enum.reduce(subkeys, merged_value, fn subkey, acc -> Keyword.put(acc, subkey, new_value[subkey]) @@ -127,6 +127,24 @@ defmodule Pleroma.ConfigDB do |> List.flatten() end + def merge(config1, config2) when is_list(config1) and is_list(config2) do + Keyword.merge(config1, config2, fn _, app1, app2 -> + if Keyword.keyword?(app1) and Keyword.keyword?(app2) do + Keyword.merge(app1, app2, &deep_merge/3) + else + app2 + end + end) + end + + defp deep_merge(_key, value1, value2) do + if Keyword.keyword?(value1) and Keyword.keyword?(value2) do + Keyword.merge(value1, value2, &deep_merge/3) + else + value2 + end + end + @full_key_update [ {:pleroma, :ecto_repos}, {:quack, :meta}, diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index cc658dc0e..30343a9f1 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -826,7 +826,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do else merged = Pleroma.Config.Holder.config() - |> DeepMerge.deep_merge(configs) + |> ConfigDB.merge(configs) |> Enum.map(fn {group, values} -> Enum.map(values, fn {key, value} -> db = -- cgit v1.2.3 From 6e88a7e5917f558fe3e9d639297086a9e8b98939 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 20 Jan 2020 21:47:44 +0300 Subject: exclude blocked user posts from search results --- lib/pleroma/activity.ex | 4 +--- lib/pleroma/activity/queries.ex | 10 ++++++++++ lib/pleroma/activity/search.ex | 11 ++++++++--- lib/pleroma/web/mastodon_api/controllers/search_controller.ex | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 510d3273c..896cbb3c5 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -312,9 +312,7 @@ defmodule Pleroma.Activity do from(u in User.Query.build(deactivated: true), select: u.ap_id) |> Repo.all() - from(activity in query, - where: activity.actor not in ^deactivated_users - ) + Activity.Queries.exclude_authors(query, deactivated_users) end defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex index 26bc1099d..79f305201 100644 --- a/lib/pleroma/activity/queries.ex +++ b/lib/pleroma/activity/queries.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Activity.Queries do @type query :: Ecto.Queryable.t() | Activity.t() alias Pleroma.Activity + alias Pleroma.User @spec by_ap_id(query, String.t()) :: query def by_ap_id(query \\ Activity, ap_id) do @@ -29,6 +30,11 @@ defmodule Pleroma.Activity.Queries do ) end + @spec by_author(query, String.t()) :: query + def by_author(query \\ Activity, %User{ap_id: ap_id}) do + from(a in query, where: a.actor == ^ap_id) + end + @spec by_object_id(query, String.t() | [String.t()]) :: query def by_object_id(query \\ Activity, object_id) @@ -72,4 +78,8 @@ defmodule Pleroma.Activity.Queries do where: fragment("(?)->>'type' != ?", activity.data, ^activity_type) ) end + + def exclude_authors(query \\ Activity, actors) do + from(activity in query, where: activity.actor not in ^actors) + end end diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex index d30a5a6a5..f96e208da 100644 --- a/lib/pleroma/activity/search.ex +++ b/lib/pleroma/activity/search.ex @@ -26,18 +26,23 @@ defmodule Pleroma.Activity.Search do |> query_with(index_type, search_query) |> maybe_restrict_local(user) |> maybe_restrict_author(author) + |> maybe_restrict_blocked(user) |> Pagination.fetch_paginated(%{"offset" => offset, "limit" => limit}, :offset) |> maybe_fetch(user, search_query) end def maybe_restrict_author(query, %User{} = author) do - from([a, o] in query, - where: a.actor == ^author.ap_id - ) + Activity.Queries.by_author(query, author) end def maybe_restrict_author(query, _), do: query + def maybe_restrict_blocked(query, %User{} = user) do + Activity.Queries.exclude_authors(query, User.blocked_users_ap_ids(user)) + end + + def maybe_restrict_blocked(query, _), do: query + defp restrict_public(q) do from([a, o] in q, where: fragment("?->>'type' = 'Create'", a.data), diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 0a929f55b..5a5db8e00 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -43,7 +43,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do result = default_values |> Enum.map(fn {resource, default_value} -> - if params["type"] == nil or params["type"] == resource do + if params["type"] in [nil, resource] do {resource, fn -> resource_search(version, resource, query, options) end} else {resource, fn -> default_value end} -- cgit v1.2.3 From dcae5914d1f7d540e3c20be5988d5e3547a349cd Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Tue, 21 Jan 2020 10:14:48 +0300 Subject: fix for db key --- lib/pleroma/config/config_db.ex | 7 ++++++- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 0091f7a1b..1afe294f4 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -205,9 +205,14 @@ defmodule Pleroma.ConfigDB do {config, sub_keys} when is_list(sub_keys) <- {config, params[:subkeys]}, old_value <- from_binary(config.value), keys <- Enum.map(sub_keys, &do_transform_string(&1)), - new_value <- Keyword.drop(old_value, keys) do + {:partial_remove, config, new_value} when new_value != [] <- + {:partial_remove, config, Keyword.drop(old_value, keys)} do ConfigDB.update(config, %{value: new_value}) else + {:partial_remove, config, []} -> + Repo.delete(config) + {:ok, nil} + {config, nil} -> Repo.delete(config) {:ok, nil} diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 30343a9f1..d45b1f7a7 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -831,7 +831,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do Enum.map(values, fn {key, value} -> db = if configs[group][key] do - ConfigDB.get_db_keys(value, key) + ConfigDB.get_db_keys(configs[group][key], key) end db_value = configs[group][key] -- cgit v1.2.3 From f01ab6cd29aaae39fef6a95ec8490223fb692499 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Tue, 21 Jan 2020 17:49:22 +0300 Subject: some refactor and tests --- lib/mix/tasks/pleroma/config.ex | 154 ++++++++++++---------- lib/pleroma/config/config_db.ex | 152 ++++++++++----------- lib/pleroma/config/holder.ex | 23 +--- lib/pleroma/config/loader.ex | 36 +++-- lib/pleroma/config/transfer_task.ex | 49 +++---- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 6 files changed, 221 insertions(+), 195 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 715b72dbe..861832451 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -19,94 +19,55 @@ defmodule Mix.Tasks.Pleroma.Config do end def run(["migrate_from_db" | options]) do - # TODO: add support for releases start_pleroma() {opts, _} = OptionParser.parse!(options, - strict: [env: :string, delete_from_db: :boolean], - aliases: [d: :delete_from_db] + strict: [env: :string, delete: :boolean], + aliases: [d: :delete] ) - with {:active?, true} <- - {:active?, Pleroma.Config.get([:configurable_from_database])}, - env when is_binary(env) <- opts[:env] || "prod", - config_path <- config_path(env), - {:ok, file} <- File.open(config_path, [:write, :utf8]) do - IO.write(file, config_header()) - - ConfigDB - |> Repo.all() - |> Enum.each(&write_to_file_with_deletion(&1, file, opts[:delete_from_db])) - - File.close(file) - System.cmd("mix", ["format", config_path]) - else - {:active?, false} -> - shell_info( - "Migration is not allowed by config. You can change this behavior in instance settings." - ) - - error -> - shell_info("Error occuried while opening file. #{inspect(error)}") - end - end - - defp config_path(env) do - path = - if Pleroma.Config.get(:release) do - :config_path - |> Pleroma.Config.get() - |> Path.dirname() - else - "config" - end - - Path.join(path, "#{env}.exported_from_db.secret.exs") + migrate_from_db(opts) end @spec migrate_to_db(Path.t() | nil) :: any() def migrate_to_db(file_path \\ nil) do if Pleroma.Config.get([:configurable_from_database]) do - user_config_file = - if Pleroma.Config.get(:release), - do: Pleroma.Config.get(:config_path), - else: "config/#{Pleroma.Config.get(:env)}.secret.exs" + config_file = + if file_path do + file_path + else + if Pleroma.Config.get(:release) do + Pleroma.Config.get(:config_path) + else + "config/#{Pleroma.Config.get(:env)}.secret.exs" + end + end - config_file = file_path || user_config_file do_migrate_to_db(config_file) else - shell_info( - "Migration is not allowed by config. You can change this behavior in instance settings." - ) + migration_error() end end - if Code.ensure_loaded?(Config.Reader) do - defp config_header, do: "import Config\r\n\r\n" - defp read_file(config_file), do: Config.Reader.read_imports!(config_file) - else - defp config_header, do: "use Mix.Config\r\n\r\n" - defp read_file(config_file), do: Mix.Config.eval!(config_file) - end - defp do_migrate_to_db(config_file) do if File.exists?(config_file) do - {custom_config, _paths} = read_file(config_file) + custom_config = + config_file + |> read_file() + |> elem(0) custom_config |> Keyword.keys() - |> Enum.each(&create(&1, custom_config[&1])) + |> Enum.each(&create(&1, custom_config)) else shell_info("To migrate settings, you must define custom settings in #{config_file}.") end end defp create(group, settings) do - Enum.reject(settings, fn {k, _v} -> - k in [Pleroma.Repo, Pleroma.Web.Endpoint, :env, :configurable_from_database] or - (group == :phoenix and k == :serve_endpoints) - end) + group + |> Pleroma.Config.Loader.filter_group(settings) |> Enum.each(fn {key, value} -> key = inspect(key) {:ok, _} = ConfigDB.update_or_create(%{group: inspect(group), key: key, value: value}) @@ -117,17 +78,70 @@ defmodule Mix.Tasks.Pleroma.Config do shell_info("Settings for group :#{group} migrated.") end - defp write_to_file_with_deletion(config, file, with_deletion) do - IO.write( - file, - "config #{config.group}, #{config.key}, #{ - inspect(ConfigDB.from_binary(config.value), limit: :infinity) - }\r\n\r\n" - ) + defp migrate_from_db(opts) do + if Pleroma.Config.get([:configurable_from_database]) do + env = opts[:env] || "prod" + + config_path = + if Pleroma.Config.get(:release) do + :config_path + |> Pleroma.Config.get() + |> Path.dirname() + else + "config" + end + |> Path.join("#{env}.exported_from_db.secret.exs") + + file = File.open!(config_path, [:write, :utf8]) + + IO.write(file, config_header()) + + ConfigDB + |> Repo.all() + |> Enum.each(&write_and_delete(&1, file, opts[:delete])) - if with_deletion do - {:ok, _} = Repo.delete(config) - shell_info("#{config.key} deleted from DB.") + :ok = File.close(file) + System.cmd("mix", ["format", config_path]) + else + migration_error() end end + + defp migration_error do + shell_error( + "Migration is not allowed in config. You can change this behavior by setting `configurable_from_database` to true." + ) + end + + if Code.ensure_loaded?(Config.Reader) do + defp config_header, do: "import Config\r\n\r\n" + defp read_file(config_file), do: Config.Reader.read_imports!(config_file) + else + defp config_header, do: "use Mix.Config\r\n\r\n" + defp read_file(config_file), do: Mix.Config.eval!(config_file) + end + + defp write_and_delete(config, file, delete?) do + config + |> write(file) + |> delete(delete?) + end + + defp write(config, file) do + value = + config.value + |> ConfigDB.from_binary() + |> inspect(limit: :infinity) + + IO.write(file, "config #{config.group}, #{config.key}, #{value}\r\n\r\n") + + config + end + + defp delete(config, true) do + {:ok, _} = Repo.delete(config) + shell_info("#{config.key} deleted from DB.") + end + + defp delete(_config, _), do: :ok end diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 1afe294f4..102e26773 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -4,14 +4,38 @@ defmodule Pleroma.ConfigDB do use Ecto.Schema + import Ecto.Changeset import Ecto.Query import Pleroma.Web.Gettext + alias __MODULE__ alias Pleroma.Repo @type t :: %__MODULE__{} + @full_key_update [ + {:pleroma, :ecto_repos}, + {:quack, :meta}, + {:mime, :types}, + {:cors_plug, [:max_age, :methods, :expose, :headers]}, + {:auto_linker, :opts}, + {:swarm, :node_blacklist}, + {:logger, :backends} + ] + + @full_subkey_update [ + {:pleroma, :assets, :mascots}, + {:pleroma, :emoji, :groups}, + {:pleroma, :workers, :retries}, + {:pleroma, :mrf_subchain, :match_actor}, + {:pleroma, :mrf_keyword, :replace} + ] + + @regex ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u + + @delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}] + schema "config" do field(:key, :string) field(:group, :string) @@ -78,37 +102,35 @@ defmodule Pleroma.ConfigDB do end end - @full_subkey_update [ - {:pleroma, :assets, :mascots}, - {:pleroma, :emoji, :groups}, - {:pleroma, :workers, :retries}, - {:pleroma, :mrf_subchain, :match_actor}, - {:pleroma, :mrf_keyword, :replace} - ] - - @spec deep_merge(atom(), atom(), keyword(), keyword()) :: keyword() - def deep_merge(group, key, old_value, new_value) do - old_keys = - old_value - |> Keyword.keys() - |> MapSet.new() + @spec merge_group(atom(), atom(), keyword(), keyword()) :: keyword() + def merge_group(group, key, old_value, new_value) do + new_keys = to_map_set(new_value) - new_keys = - new_value - |> Keyword.keys() - |> MapSet.new() - - intersect_keys = old_keys |> MapSet.intersection(new_keys) |> MapSet.to_list() - - subkeys = sub_key_full_update(group, key, intersect_keys) + intersect_keys = + old_value |> to_map_set() |> MapSet.intersection(new_keys) |> MapSet.to_list() merged_value = ConfigDB.merge(old_value, new_value) - Enum.reduce(subkeys, merged_value, fn subkey, acc -> + @full_subkey_update + |> Enum.map(fn + {g, k, subkey} when g == group and k == key -> + if subkey in intersect_keys, do: subkey, else: [] + + _ -> + [] + end) + |> List.flatten() + |> Enum.reduce(merged_value, fn subkey, acc -> Keyword.put(acc, subkey, new_value[subkey]) end) end + defp to_map_set(keyword) do + keyword + |> Keyword.keys() + |> MapSet.new() + end + @spec sub_key_full_update?(atom(), atom(), [Keyword.key()]) :: boolean() def sub_key_full_update?(group, key, subkeys) do Enum.any?(@full_subkey_update, fn {g, k, subkey} -> @@ -116,17 +138,7 @@ defmodule Pleroma.ConfigDB do end) end - defp sub_key_full_update(group, key, subkeys) do - Enum.map(@full_subkey_update, fn - {g, k, subkey} when g == group and k == key -> - if subkey in subkeys, do: subkey, else: [] - - _ -> - [] - end) - |> List.flatten() - end - + @spec merge(keyword(), keyword()) :: keyword() def merge(config1, config2) when is_list(config1) and is_list(config2) do Keyword.merge(config1, config2, fn _, app1, app2 -> if Keyword.keyword?(app1) and Keyword.keyword?(app2) do @@ -145,31 +157,6 @@ defmodule Pleroma.ConfigDB do end end - @full_key_update [ - {:pleroma, :ecto_repos}, - {:quack, :meta}, - {:mime, :types}, - {:cors_plug, [:max_age, :methods, :expose, :headers]}, - {:auto_linker, :opts}, - {:swarm, :node_blacklist}, - {:logger, :backends} - ] - - defp only_full_update?(%ConfigDB{} = config) do - config_group = ConfigDB.from_string(config.group) - config_key = ConfigDB.from_string(config.key) - - Enum.any?(@full_key_update, fn - {group, key} when is_list(key) -> - config_group == group and config_key in key - - {group, key} -> - config_group == group and config_key == key - end) - end - - defp can_be_partially_updated?(%ConfigDB{} = config), do: not only_full_update?(config) - @spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} def update_or_create(params) do search_opts = Map.take(params, [:group, :key]) @@ -181,7 +168,7 @@ defmodule Pleroma.ConfigDB do transformed_value <- do_transform(params[:value]), {:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config}, new_value <- - deep_merge( + merge_group( ConfigDB.from_string(config.group), ConfigDB.from_string(config.key), old_value, @@ -197,6 +184,21 @@ defmodule Pleroma.ConfigDB do end end + defp can_be_partially_updated?(%ConfigDB{} = config), do: not only_full_update?(config) + + defp only_full_update?(%ConfigDB{} = config) do + config_group = ConfigDB.from_string(config.group) + config_key = ConfigDB.from_string(config.key) + + Enum.any?(@full_key_update, fn + {group, key} when is_list(key) -> + config_group == group and config_key in key + + {group, key} -> + config_group == group and config_key == key + end) + end + @spec delete(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} | {:ok, nil} def delete(params) do search_opts = Map.delete(params, :subkeys) @@ -286,18 +288,24 @@ defmodule Pleroma.ConfigDB do } end - # TODO: will become useless after removing hackney defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]} - defp do_convert(entity) when is_tuple(entity), - do: %{"tuple" => do_convert(Tuple.to_list(entity))} + defp do_convert(entity) when is_tuple(entity) do + value = + entity + |> Tuple.to_list() + |> do_convert() + + %{"tuple" => value} + end - defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity), - do: entity + defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity) do + entity + end defp do_convert(entity) when is_atom(entity) and entity in [:"tlsv1.1", :"tlsv1.2", :"tlsv1.3"] do - ":#{to_string(entity)}" + ":#{entity}" end defp do_convert(entity) when is_atom(entity), do: inspect(entity) @@ -325,7 +333,6 @@ defmodule Pleroma.ConfigDB do {:proxy_url, {do_transform_string(type), parse_host(host), port}} end - # TODO: will become useless after removing hackney defp do_transform(%{"tuple" => [":partial_chain", entity]}) do {partial_chain, []} = entity @@ -369,10 +376,9 @@ defmodule Pleroma.ConfigDB do end end - @delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}] - - defp find_valid_delimiter([], _string, _), - do: raise(ArgumentError, message: "valid delimiter for Regex expression not found") + defp find_valid_delimiter([], _string, _) do + raise(ArgumentError, message: "valid delimiter for Regex expression not found") + end defp find_valid_delimiter([{leading, closing} = delimiter | others], pattern, regex_delimiter) when is_tuple(delimiter) do @@ -391,11 +397,9 @@ defmodule Pleroma.ConfigDB do end end - @regex_parts ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u - defp do_transform_string("~r" <> _pattern = regex) do with %{"modifier" => modifier, "pattern" => pattern, "delimiter" => regex_delimiter} <- - Regex.named_captures(@regex_parts, regex), + Regex.named_captures(@regex, regex), {:ok, {leading, closing}} <- find_valid_delimiter(@delimiters, pattern, regex_delimiter), {result, _} <- Code.eval_string("~r#{leading}#{pattern}#{closing}#{modifier}") do result diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex index 0fa7c5bf7..d4fe892af 100644 --- a/lib/pleroma/config/holder.ex +++ b/lib/pleroma/config/holder.ex @@ -1,29 +1,16 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Config.Holder do @config Pleroma.Config.Loader.load_and_merge() @spec config() :: keyword() - def config do - @config - |> Keyword.keys() - |> Enum.map(&filter(&1, config(&1))) - |> List.flatten() - end + def config, do: @config @spec config(atom()) :: any() def config(group), do: @config[group] @spec config(atom(), atom()) :: any() def config(group, key), do: @config[group][key] - - defp filter(group, settings) when group not in [:swarm] do - filtered = - Enum.reject(settings, fn {k, _v} -> - k in [Pleroma.Repo, Pleroma.Web.Endpoint, :env, :configurable_from_database] or - (group == :phoenix and k == :serve_endpoints) - end) - - {group, filtered} - end - - defp filter(_, _), do: [] end diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex index b13b6eaf4..68b247381 100644 --- a/lib/pleroma/config/loader.ex +++ b/lib/pleroma/config/loader.ex @@ -1,6 +1,19 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Config.Loader do @paths ["config/config.exs", "config/#{Mix.env()}.exs"] + @reject_keys [ + Pleroma.Repo, + Pleroma.Web.Endpoint, + :env, + :configurable_from_database, + :database, + :swarm + ] + if Code.ensure_loaded?(Config.Reader) do @spec load(Path.t()) :: keyword() def load(path), do: Config.Reader.read!(path) @@ -10,8 +23,9 @@ defmodule Pleroma.Config.Loader do # support for Elixir less than 1.9 @spec load(Path.t()) :: keyword() def load(path) do - {config, _paths} = Mix.Config.eval!(path) - config + path + |> Mix.Config.eval!() + |> elem(0) end defp do_merge(conf1, conf2), do: Mix.Config.merge(conf1, conf2) @@ -26,14 +40,20 @@ defmodule Pleroma.Config.Loader do all_paths |> Enum.map(&load(&1)) - |> merge() + |> Enum.reduce([], &do_merge(&2, &1)) + |> filter() end - @spec merge([keyword()], keyword()) :: keyword() - def merge(configs, acc \\ []) - def merge([], acc), do: acc + defp filter(configs) do + configs + |> Keyword.keys() + |> Enum.reduce([], &Keyword.put(&2, &1, filter_group(&1, configs))) + end - def merge([config | others], acc) do - merge(others, do_merge(acc, config)) + @spec filter_group(atom(), keyword()) :: keyword() + def filter_group(group, configs) do + Enum.reject(configs[group], fn {key, _v} -> + key in @reject_keys or (group == :phoenix and key == :serve_endpoints) + end) end end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 9b571d5d9..00c8790f8 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -37,31 +37,29 @@ defmodule Pleroma.Config.TransferTask do group = ConfigDB.from_string(setting.group) value = ConfigDB.from_binary(setting.value) - if group != :phoenix and key != :serve_endpoints do - default = Pleroma.Config.Holder.config(group, key) + default = Pleroma.Config.Holder.config(group, key) - merged_value = - if can_be_merged?(default, value) do - ConfigDB.deep_merge(group, key, default, value) - else - value - end + merged_value = + if can_be_merged?(default, value) do + ConfigDB.merge_group(group, key, default, value) + else + value + end - :ok = Application.put_env(group, key, merged_value) + :ok = Application.put_env(group, key, merged_value) - if group != :logger do - group + if group != :logger do + group + else + # change logger configuration in runtime, without restart + if Keyword.keyword?(merged_value) and + key not in [:compile_time_application, :backends, :compile_time_purge_matching] do + Logger.configure_backend(key, merged_value) else - # change logger configuration in runtime, without restart - if Keyword.keyword?(merged_value) and - key not in [:compile_time_application, :backends, :compile_time_purge_matching] do - Logger.configure_backend(key, merged_value) - else - Logger.configure([{key, merged_value}]) - end - - nil + Logger.configure([{key, merged_value}]) end + + nil end rescue e -> @@ -80,13 +78,16 @@ defmodule Pleroma.Config.TransferTask do :ok <- Application.stop(app) do :ok = Application.start(app) else - nil -> Logger.warn("#{app} is not started.") - error -> Logger.warn(inspect(error)) + nil -> + Logger.warn("#{app} is not started.") + + error -> + error + |> inspect() + |> Logger.warn() end end - defp can_be_merged?(val1, val2) when is_map(val1) and is_map(val2), do: true - defp can_be_merged?(val1, val2) when is_list(val1) and is_list(val2) do Keyword.keyword?(val1) and Keyword.keyword?(val2) end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index d5230f9aa..1b09d137b 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -848,7 +848,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do merged_value = if !is_nil(db_value) and Keyword.keyword?(db_value) and ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do - ConfigDB.deep_merge(group, key, value, db_value) + ConfigDB.merge_group(group, key, value, db_value) else value end -- cgit v1.2.3 From d5f8a88a37cb4a2341f11d5e39adfaba024e3486 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Wed, 22 Jan 2020 15:14:11 +0300 Subject: support for updating env after settings deletion --- lib/pleroma/config/config_db.ex | 4 +- lib/pleroma/config/transfer_task.ex | 58 +++++++++++++++-------- lib/pleroma/web/admin_api/admin_api_controller.ex | 24 +++++----- 3 files changed, 51 insertions(+), 35 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 102e26773..91a1aa0cc 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -199,7 +199,7 @@ defmodule Pleroma.ConfigDB do end) end - @spec delete(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} | {:ok, nil} + @spec delete(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()} def delete(params) do search_opts = Map.delete(params, :subkeys) @@ -213,11 +213,9 @@ defmodule Pleroma.ConfigDB do else {:partial_remove, config, []} -> Repo.delete(config) - {:ok, nil} {config, nil} -> Repo.delete(config) - {:ok, nil} nil -> err = diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 00c8790f8..d54f38ee4 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -16,37 +16,36 @@ defmodule Pleroma.Config.TransferTask do :ignore end - def load_and_update_env do + @spec load_and_update_env([ConfigDB.t()]) :: :ok | false + def load_and_update_env(deleted \\ []) do with true <- Pleroma.Config.get(:configurable_from_database), true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"), started_applications <- Application.started_applications() do # We need to restart applications for loaded settings take effect - ConfigDB - |> Repo.all() - |> Enum.map(&update_env(&1)) + in_db = Repo.all(ConfigDB) + + with_deleted = in_db ++ deleted + + with_deleted + |> Enum.map(&merge_and_update(&1)) |> Enum.uniq() # TODO: some problem with prometheus after restart! |> Enum.reject(&(&1 in [:pleroma, nil, :prometheus])) |> Enum.each(&restart(started_applications, &1)) + + :ok end end - defp update_env(setting) do + defp merge_and_update(setting) do try do key = ConfigDB.from_string(setting.key) group = ConfigDB.from_string(setting.group) - value = ConfigDB.from_binary(setting.value) default = Pleroma.Config.Holder.config(group, key) + merged_value = merge_value(setting, default, group, key) - merged_value = - if can_be_merged?(default, value) do - ConfigDB.merge_group(group, key, default, value) - else - value - end - - :ok = Application.put_env(group, key, merged_value) + :ok = update_env(group, key, merged_value) if group != :logger do group @@ -62,17 +61,36 @@ defmodule Pleroma.Config.TransferTask do nil end rescue - e -> - Logger.warn( - "updating env causes error, group: #{inspect(setting.group)}, key: #{ - inspect(setting.key) - }, value: #{inspect(ConfigDB.from_binary(setting.value))}, error: #{inspect(e)}" - ) + error -> + error_msg = + "updating env causes error, group: " <> + inspect(setting.group) <> + " key: " <> + inspect(setting.key) <> + " value: " <> + inspect(ConfigDB.from_binary(setting.value)) <> " error: " <> inspect(error) + + Logger.warn(error_msg) nil end end + defp merge_value(%{__meta__: %{state: :deleted}}, default, _group, _key), do: default + + defp merge_value(setting, default, group, key) do + value = ConfigDB.from_binary(setting.value) + + if can_be_merged?(default, value) do + ConfigDB.merge_group(group, key, default, value) + else + value + end + end + + defp update_env(group, key, nil), do: Application.delete_env(group, key) + defp update_env(group, key, value), do: Application.put_env(group, key, value) + defp restart(started_applications, app) do with {^app, _, _} <- List.keyfind(started_applications, app, 0), :ok <- Application.stop(app) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 1b09d137b..2314d3274 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -871,26 +871,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do def config_update(conn, %{"configs" => configs}) do with :ok <- configurable_from_database(conn) do - updated = + {_errors, results} = Enum.map(configs, fn %{"group" => group, "key" => key, "delete" => true} = params -> - with {:ok, config} <- - ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]}) do - config - end + ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]}) %{"group" => group, "key" => key, "value" => value} -> - with {:ok, config} <- - ConfigDB.update_or_create(%{group: group, key: key, value: value}) do - config - end + ConfigDB.update_or_create(%{group: group, key: key, value: value}) end) - |> Enum.reject(&is_nil(&1)) - |> Enum.map(fn config -> + |> Enum.split_with(fn result -> elem(result, 0) == :error end) + + {deleted, updated} = + results + |> Enum.map(fn {:ok, config} -> Map.put(config, :db, ConfigDB.get_db_keys(config)) end) + |> Enum.split_with(fn config -> + Ecto.get_meta(config, :state) == :deleted + end) - Pleroma.Config.TransferTask.load_and_update_env() + Pleroma.Config.TransferTask.load_and_update_env(deleted) Mix.Tasks.Pleroma.Config.run([ "migrate_from_db", -- cgit v1.2.3 From dd3fc50ea41871c6c02076cf2786c2488d4cf3ca Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 22 Jan 2020 13:57:42 +0100 Subject: Emoji reactions: Change cache and reply format --- lib/pleroma/web/activity_pub/utils.ex | 64 ++++++++++++++-------- lib/pleroma/web/mastodon_api/views/status_view.ex | 7 +-- .../controllers/pleroma_api_controller.ex | 8 +-- 3 files changed, 47 insertions(+), 32 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index db7084246..4def431f1 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -312,19 +312,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Map.put("content", emoji) end - @spec update_element_in_object(String.t(), list(any), Object.t()) :: + @spec update_element_in_object(String.t(), list(any), Object.t(), integer() | nil) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} - def update_element_in_object(property, element, object) do + def update_element_in_object(property, element, object, count \\ nil) do length = - if is_map(element) do - element - |> Map.values() - |> List.flatten() - |> length() - else - element - |> length() - end + count || + length(element) data = Map.merge( @@ -344,29 +337,52 @@ defmodule Pleroma.Web.ActivityPub.Utils do %Activity{data: %{"content" => emoji, "actor" => actor}}, object ) do - reactions = object.data["reactions"] || %{} - emoji_actors = reactions[emoji] || [] - new_emoji_actors = [actor | emoji_actors] |> Enum.uniq() - new_reactions = Map.put(reactions, emoji, new_emoji_actors) - update_element_in_object("reaction", new_reactions, object) + reactions = object.data["reactions"] || [] + + new_reactions = + case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do + nil -> + reactions ++ [[emoji, [actor]]] + + index -> + List.update_at( + reactions, + index, + fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end + ) + end + + count = emoji_count(new_reactions) + + update_element_in_object("reaction", new_reactions, object, count) + end + + def emoji_count(reactions_list) do + Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end) end def remove_emoji_reaction_from_object( %Activity{data: %{"content" => emoji, "actor" => actor}}, object ) do - reactions = object.data["reactions"] || %{} - emoji_actors = reactions[emoji] || [] - new_emoji_actors = List.delete(emoji_actors, actor) + reactions = object.data["reactions"] || [] new_reactions = - if new_emoji_actors == [] do - Map.delete(reactions, emoji) - else - Map.put(reactions, emoji, new_emoji_actors) + case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do + nil -> + reactions + + index -> + List.update_at( + reactions, + index, + fn [emoji, users] -> [emoji, List.delete(users, actor)] end + ) + |> Enum.reject(fn [_, users] -> Enum.empty?(users) end) end - update_element_in_object("reaction", new_reactions, object) + count = emoji_count(new_reactions) + update_element_in_object("reaction", new_reactions, object, count) end @spec add_like_to_object(Activity.t(), Object.t()) :: diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index b59ac39bc..64a97896a 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -255,12 +255,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do emoji_reactions = with %{data: %{"reactions" => emoji_reactions}} <- object do - Enum.map(emoji_reactions, fn {emoji, users} -> - {emoji, length(users)} + Enum.map(emoji_reactions, fn [emoji, users] -> + [emoji, length(users)] end) - |> Enum.into(%{}) else - _ -> %{} + _ -> [] end %{ diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 3285dc11b..bb19836ae 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -43,21 +43,21 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), - %Object{data: %{"reactions" => emoji_reactions}} <- Object.normalize(activity) do + %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <- + Object.normalize(activity) do reactions = emoji_reactions - |> Enum.map(fn {emoji, users} -> + |> Enum.map(fn [emoji, users] -> users = Enum.map(users, &User.get_cached_by_ap_id/1) {emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})} end) - |> Enum.into(%{}) conn |> json(reactions) else _e -> conn - |> json(%{}) + |> json([]) end end -- cgit v1.2.3 From 615b72238eb41f631c43e85d40c423017e848044 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 22 Jan 2020 20:06:12 +0100 Subject: Notifications: Add emoji reaction notifications --- lib/pleroma/activity.ex | 3 ++- lib/pleroma/notification.ex | 4 +-- .../web/mastodon_api/views/notification_view.ex | 31 +++++++++++++++++----- 3 files changed, 29 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 896cbb3c5..0f8fce774 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -30,7 +30,8 @@ defmodule Pleroma.Activity do "Follow" => "follow", "Announce" => "reblog", "Like" => "favourite", - "Move" => "move" + "Move" => "move", + "EmojiReaction" => "pleroma:emoji_reaction" } @mastodon_to_ap_notification_types for {k, v} <- @mastodon_notification_types, diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 8f3e46af9..d04a65a1e 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -294,7 +294,7 @@ defmodule Pleroma.Notification do end def create_notifications(%Activity{data: %{"type" => type}} = activity) - when type in ["Like", "Announce", "Follow", "Move"] do + when type in ["Like", "Announce", "Follow", "Move", "EmojiReaction"] do notifications = activity |> get_notified_from_activity() @@ -322,7 +322,7 @@ defmodule Pleroma.Notification do def get_notified_from_activity(activity, local_only \\ true) def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only) - when type in ["Create", "Like", "Announce", "Follow", "Move"] do + when type in ["Create", "Like", "Announce", "Follow", "Move", "EmojiReaction"] do [] |> Utils.maybe_notify_to_recipients(activity) |> Utils.maybe_notify_mentioned_recipients(activity) diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex index ddd7f5318..360ec10f0 100644 --- a/lib/pleroma/web/mastodon_api/views/notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex @@ -37,18 +37,37 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do } case mastodon_type do - "mention" -> put_status(response, activity, user) - "favourite" -> put_status(response, parent_activity, user) - "reblog" -> put_status(response, parent_activity, user) - "move" -> put_target(response, activity, user) - "follow" -> response - _ -> nil + "mention" -> + put_status(response, activity, user) + + "favourite" -> + put_status(response, parent_activity, user) + + "reblog" -> + put_status(response, parent_activity, user) + + "move" -> + put_target(response, activity, user) + + "follow" -> + response + + "pleroma:emoji_reaction" -> + put_status(response, parent_activity, user) |> put_emoji(activity) + + _ -> + nil end else _ -> nil end end + defp put_emoji(response, activity) do + response + |> Map.put(:emoji, activity.data["content"]) + end + defp put_status(response, activity, user) do Map.put(response, :status, StatusView.render("show.json", %{activity: activity, for: user})) end -- cgit v1.2.3 From 34fc0ca05362d2dfd69352e8f4004b26d39315ac Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 23 Jan 2020 12:34:34 +0100 Subject: Emoji reactions: Add sanity checks for the cache --- lib/pleroma/web/activity_pub/utils.ex | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 4def431f1..4f7fdaf38 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -337,7 +337,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do %Activity{data: %{"content" => emoji, "actor" => actor}}, object ) do - reactions = object.data["reactions"] || [] + reactions = get_cached_emoji_reactions(object) new_reactions = case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do @@ -365,7 +365,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do %Activity{data: %{"content" => emoji, "actor" => actor}}, object ) do - reactions = object.data["reactions"] || [] + reactions = get_cached_emoji_reactions(object) new_reactions = case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do @@ -385,6 +385,14 @@ defmodule Pleroma.Web.ActivityPub.Utils do update_element_in_object("reaction", new_reactions, object, count) end + def get_cached_emoji_reactions(object) do + if is_list(object.data["reactions"]) do + object.data["reactions"] + else + [] + end + end + @spec add_like_to_object(Activity.t(), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do -- cgit v1.2.3 From 4344c5d5b99cedcd08e168650af2f641ef8c6f0b Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 23 Jan 2020 17:23:02 +0300 Subject: truncate config table on migrate to db task --- lib/mix/tasks/pleroma/config.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 861832451..8098e9bab 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -52,6 +52,8 @@ defmodule Mix.Tasks.Pleroma.Config do defp do_migrate_to_db(config_file) do if File.exists?(config_file) do + Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;") + custom_config = config_file |> read_file() -- cgit v1.2.3 From e8e57e398f701497b9989c19c36c20fd227393ac Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 23 Jan 2020 17:48:45 +0300 Subject: restart config id after truncate --- lib/mix/tasks/pleroma/config.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 8098e9bab..3e76d2c97 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -53,6 +53,7 @@ defmodule Mix.Tasks.Pleroma.Config do defp do_migrate_to_db(config_file) do if File.exists?(config_file) do Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;") + Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;") custom_config = config_file -- cgit v1.2.3 From 6cd2e851d9d61ce82edf83ced79c9d4c613c0373 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 23 Jan 2020 18:21:29 +0300 Subject: parsing Swoosh modules --- lib/pleroma/config/config_db.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 91a1aa0cc..be6688095 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -416,7 +416,7 @@ defmodule Pleroma.ConfigDB do @spec is_module_name?(String.t()) :: boolean() def is_module_name?(string) do - Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth)\./, string) or + Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth|Swoosh)\./, string) or string in ["Oban", "Ueberauth", "ExSyslogger"] end end -- cgit v1.2.3 From 6a0f0ac4a2a4387fd08c723a917216238f5fe8b3 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 24 Jan 2020 12:22:26 +0300 Subject: fix for non existing atom --- lib/pleroma/config/config_db.ex | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index be6688095..119251bee 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -236,15 +236,7 @@ defmodule Pleroma.ConfigDB do end @spec from_string(String.t()) :: atom() | no_return() - def from_string(":" <> entity), do: String.to_existing_atom(entity) - - def from_string(entity) when is_binary(entity) do - if is_module_name?(entity) do - String.to_existing_atom("Elixir.#{entity}") - else - entity - end - end + def from_string(string), do: do_transform_string(string) @spec convert(any()) :: any() def convert(entity), do: do_convert(entity) -- cgit v1.2.3 From 347f3ed2c625c49588b62b2d743c8d06221eb14b Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 24 Jan 2020 10:52:24 +0100 Subject: Emoji reactions: Change api format once more --- lib/pleroma/web/mastodon_api/views/status_view.ex | 2 +- lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 64a97896a..e60ef709b 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -256,7 +256,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do emoji_reactions = with %{data: %{"reactions" => emoji_reactions}} <- object do Enum.map(emoji_reactions, fn [emoji, users] -> - [emoji, length(users)] + %{emoji: emoji, count: length(users)} end) else _ -> [] diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index bb19836ae..cd1c0764f 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -49,7 +49,12 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do emoji_reactions |> Enum.map(fn [emoji, users] -> users = Enum.map(users, &User.get_cached_by_ap_id/1) - {emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})} + + %{ + emoji: emoji, + count: length(users), + accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}) + } end) conn -- cgit v1.2.3 From 99c0a11c584ac13c368a3d8372f9e914cef14a06 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 24 Jan 2020 22:08:10 +0300 Subject: added atom feed --- lib/pleroma/web/feed/feed_view.ex | 16 ++++++- lib/pleroma/web/feed/tag_controller.ex | 11 ++--- .../web/templates/feed/feed/_activity.xml.eex | 2 +- .../web/templates/feed/feed/_tag_activity.atom.eex | 51 ++++++++++++++++++++++ .../web/templates/feed/feed/_tag_author.atom.eex | 18 ++++++++ lib/pleroma/web/templates/feed/feed/tag.atom.eex | 22 ++++++++++ lib/pleroma/web/templates/feed/feed/tag.rss.eex | 15 +++++++ lib/pleroma/web/templates/feed/feed/tag.xml.eex | 15 ------- 8 files changed, 127 insertions(+), 23 deletions(-) create mode 100644 lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex create mode 100644 lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex create mode 100644 lib/pleroma/web/templates/feed/feed/tag.atom.eex create mode 100644 lib/pleroma/web/templates/feed/feed/tag.rss.eex delete mode 100644 lib/pleroma/web/templates/feed/feed/tag.xml.eex (limited to 'lib') diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 2e7db1ebb..334802e0a 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -22,16 +22,28 @@ defmodule Pleroma.Web.Feed.FeedView do def pub_date(%DateTime{} = date), do: Timex.format!(date, "{RFC822}") - def prepare_activity(activity) do + def prepare_activity(activity, opts \\ []) do object = activity_object(activity) + actor = + if opts[:actor] do + Pleroma.User.get_cached_by_ap_id(activity.actor) + end + %{ activity: activity, data: Map.get(object, :data), - object: object + object: object, + actor: actor } end + def most_recent_update(activities) do + with %{updated_at: updated_at} <- List.first(activities) do + NaiveDateTime.to_iso8601(updated_at) + end + end + def most_recent_update(activities, user) do (List.first(activities) || user).updated_at |> NaiveDateTime.to_iso8601() diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex index 97ce147de..9b722336c 100644 --- a/lib/pleroma/web/feed/tag_controller.ex +++ b/lib/pleroma/web/feed/tag_controller.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.Feed.TagController do import Pleroma.Web.ControllerHelper, only: [put_in_if_exist: 3] def feed(conn, %{"tag" => raw_tag} = params) do - tag = parse_tag(raw_tag) + {format, tag} = parse_tag(raw_tag) activities = %{"type" => ["Create"], "whole_db" => true, "tag" => tag} @@ -22,19 +22,20 @@ defmodule Pleroma.Web.Feed.TagController do conn |> put_resp_content_type("application/atom+xml") |> put_view(FeedView) - |> render("tag.xml", + |> render("tag.#{format}", activities: activities, tag: tag, feed_config: Config.get([:feed]) ) end + @spec parse_tag(binary() | any()) :: {format :: String.t(), tag :: String.t()} defp parse_tag(raw_tag) when is_binary(raw_tag) do case Enum.reverse(String.split(raw_tag, ".")) do - [format | tag] when format in ["atom", "rss"] -> Enum.join(tag, ".") - _ -> raw_tag + [format | tag] when format in ["atom", "rss"] -> {format, Enum.join(tag, ".")} + _ -> {"rss", raw_tag} end end - defp parse_tag(raw_tag), do: raw_tag + defp parse_tag(raw_tag), do: {"rss", raw_tag} end diff --git a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_activity.xml.eex index 514eacaed..ac8a75009 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.xml.eex @@ -9,7 +9,7 @@ <%= activity_context(@activity) %> - + <%= if @data["summary"] do %> <%= @data["summary"] %> diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex new file mode 100644 index 000000000..da4fa6d6c --- /dev/null +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex @@ -0,0 +1,51 @@ + + http://activitystrea.ms/schema/1.0/note + http://activitystrea.ms/schema/1.0/post + + <%= render @view_module, "_tag_author.atom", assigns %> + + <%= @data["id"] %> + <%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %> + <%= activity_content(@object) %> + + <%= if @activity.local do %> + + + <% else %> + + <% end %> + + <%= @data["published"] %> + <%= @data["published"] %> + + + <%= activity_context(@activity) %> + + + + <%= if @data["summary"] do %> + <%= @data["summary"] %> + <% end %> + + <%= for id <- @activity.recipients do %> + <%= if id == Pleroma.Constants.as_public() do %> + + <% else %> + <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %> + + <% end %> + <% end %> + <% end %> + + <%= for tag <- @data["tag"] || [] do %> + + <% end %> + + <%= for {emoji, file} <- @data["emoji"] || %{} do %> + + <% end %> + diff --git a/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex new file mode 100644 index 000000000..997c4936e --- /dev/null +++ b/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex @@ -0,0 +1,18 @@ + + http://activitystrea.ms/schema/1.0/person + <%= @actor.ap_id %> + <%= @actor.ap_id %> + <%= @actor.nickname %> + <%= escape(@actor.bio) %> + + <%= if User.banner_url(@actor) do %> + + <% end %> + <%= if @actor.local do %> + true + <% end %> + + <%= @actor.nickname %> + <%= @actor.name %> + <%= escape(@actor.bio) %> + diff --git a/lib/pleroma/web/templates/feed/feed/tag.atom.eex b/lib/pleroma/web/templates/feed/feed/tag.atom.eex new file mode 100644 index 000000000..a288539ed --- /dev/null +++ b/lib/pleroma/web/templates/feed/feed/tag.atom.eex @@ -0,0 +1,22 @@ + + + + + <%= '#{tag_feed_url(@conn, :feed, @tag)}.rss' %> + #<%= @tag %> + + These are public toots tagged with #<%= @tag %>. You can interact with them if you have an account anywhere in the fediverse. + <%= feed_logo() %> + <%= most_recent_update(@activities) %> + + <%= for activity <- @activities do %> + <%= render @view_module, "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> + <% end %> + diff --git a/lib/pleroma/web/templates/feed/feed/tag.rss.eex b/lib/pleroma/web/templates/feed/feed/tag.rss.eex new file mode 100644 index 000000000..eeda01a04 --- /dev/null +++ b/lib/pleroma/web/templates/feed/feed/tag.rss.eex @@ -0,0 +1,15 @@ + + + + + + #<%= @tag %> + These are public toots tagged with #<%= @tag %>. You can interact with them if you have an account anywhere in the fediverse. + <%= '#{tag_feed_url(@conn, :feed, @tag)}.rss' %> + <%= feed_logo() %> + 2b90d9 + <%= for activity <- @activities do %> + <%= render @view_module, "_tag_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> + <% end %> + + diff --git a/lib/pleroma/web/templates/feed/feed/tag.xml.eex b/lib/pleroma/web/templates/feed/feed/tag.xml.eex deleted file mode 100644 index eeda01a04..000000000 --- a/lib/pleroma/web/templates/feed/feed/tag.xml.eex +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - #<%= @tag %> - These are public toots tagged with #<%= @tag %>. You can interact with them if you have an account anywhere in the fediverse. - <%= '#{tag_feed_url(@conn, :feed, @tag)}.rss' %> - <%= feed_logo() %> - 2b90d9 - <%= for activity <- @activities do %> - <%= render @view_module, "_tag_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> - <% end %> - - -- cgit v1.2.3 From 6252e82f85d84c909871d3741da5c835ca2ca944 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Sat, 25 Jan 2020 10:33:27 +0300 Subject: respect settings from database in mix tasks --- lib/mix/tasks/pleroma/emoji.ex | 2 ++ lib/mix/tasks/pleroma/robotstxt.ex | 1 + 2 files changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index 35669af27..24d999707 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -9,6 +9,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md") def run(["ls-packs" | args]) do + Mix.Pleroma.start_pleroma() Application.ensure_all_started(:hackney) {options, [], []} = parse_global_opts(args) @@ -35,6 +36,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do end def run(["get-packs" | args]) do + Mix.Pleroma.start_pleroma() Application.ensure_all_started(:hackney) {options, pack_names, []} = parse_global_opts(args) diff --git a/lib/mix/tasks/pleroma/robotstxt.ex b/lib/mix/tasks/pleroma/robotstxt.ex index 2128e1cd6..e99dd8502 100644 --- a/lib/mix/tasks/pleroma/robotstxt.ex +++ b/lib/mix/tasks/pleroma/robotstxt.ex @@ -18,6 +18,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxt do """ def run(["disallow_all"]) do + Mix.Pleroma.start_pleroma() static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/") if !File.exists?(static_dir) do -- cgit v1.2.3 From de4102b2475f46fff238cfa3aec7aae1bdfd60f4 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Sat, 25 Jan 2020 10:39:10 +0300 Subject: can be changed in runtime --- lib/pleroma/web/mastodon_api/views/app_view.ex | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex index f52b693a6..beba89edb 100644 --- a/lib/pleroma/web/mastodon_api/views/app_view.ex +++ b/lib/pleroma/web/mastodon_api/views/app_view.ex @@ -7,10 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.AppView do alias Pleroma.Web.OAuth.App - @vapid_key :web_push_encryption - |> Application.get_env(:vapid_details, []) - |> Keyword.get(:public_key) - def render("show.json", %{app: %App{} = app}) do %{ id: app.id |> to_string, @@ -32,8 +28,10 @@ defmodule Pleroma.Web.MastodonAPI.AppView do end defp with_vapid_key(data) do - if @vapid_key do - Map.put(data, "vapid_key", @vapid_key) + vapid_key = Application.get_env(:web_push_encryption, :vapid_details, [])[:public_key] + + if vapid_key do + Map.put(data, "vapid_key", vapid_key) else data end -- cgit v1.2.3 From 86c4b76bf095cec70572323a8932dabfef7231bf Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Mon, 27 Jan 2020 04:01:50 +0300 Subject: Fix typo --- lib/pleroma/workers/attachments_cleanup_worker.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index 3f421db40..595001ccb 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -37,7 +37,7 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do ) # The query above can be time consumptive on large instances until we # refactor how uploads are stored - |> Repo.all(timout: :infinity) + |> Repo.all(timeout: :infinity) # we should delete 1 object for any given attachment, but don't delete # files if there are more than 1 object for it |> Enum.reduce(%{}, fn %{ -- cgit v1.2.3 From dabd535e436789e64f6630460bfadd2f49dcf069 Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Mon, 27 Jan 2020 13:21:50 +0000 Subject: Remove user recommendation by third party engine --- .../controllers/suggestion_controller.ex | 58 +--------------------- lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 9 +--- 2 files changed, 3 insertions(+), 64 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex index fe71c36af..b9cc8f104 100644 --- a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex @@ -7,62 +7,8 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionController do require Logger - alias Pleroma.Config - alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.User - alias Pleroma.Web.MediaProxy - - action_fallback(Pleroma.Web.MastodonAPI.FallbackController) - - plug(OAuthScopesPlug, %{scopes: ["read"]} when action == :index) - - plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) - @doc "GET /api/v1/suggestions" - def index(%{assigns: %{user: user}} = conn, _) do - if Config.get([:suggestions, :enabled], false) do - with {:ok, data} <- fetch_suggestions(user) do - limit = Config.get([:suggestions, :limit], 23) - - data = - data - |> Enum.slice(0, limit) - |> Enum.map(fn x -> - x - |> Map.put("id", fetch_suggestion_id(x)) - |> Map.put("avatar", MediaProxy.url(x["avatar"])) - |> Map.put("avatar_static", MediaProxy.url(x["avatar_static"])) - end) - - json(conn, data) - end - else - json(conn, []) - end - end - - defp fetch_suggestions(user) do - api = Config.get([:suggestions, :third_party_engine], "") - timeout = Config.get([:suggestions, :timeout], 5000) - host = Config.get([Pleroma.Web.Endpoint, :url, :host]) - - url = - api - |> String.replace("{{host}}", host) - |> String.replace("{{user}}", user.nickname) - - with {:ok, %{status: 200, body: body}} <- - Pleroma.HTTP.get(url, [], adapter: [recv_timeout: timeout, pool: :default]) do - Jason.decode(body) - else - e -> Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}") - end - end - - defp fetch_suggestion_id(attrs) do - case User.get_or_fetch(attrs["acct"]) do - {:ok, %User{id: id}} -> id - _ -> 0 - end + def index(conn, _) do + json(conn, []) end end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index abcf46034..03c35cc2a 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -69,9 +69,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do if Config.get([:chat, :enabled]) do "chat" end, - if Config.get([:suggestions, :enabled]) do - "suggestions" - end, if Config.get([:instance, :allow_relay]) do "relay" end, @@ -104,11 +101,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do nodeDescription: Config.get([:instance, :description]), private: !Config.get([:instance, :public], true), suggestions: %{ - enabled: Config.get([:suggestions, :enabled], false), - thirdPartyEngine: Config.get([:suggestions, :third_party_engine], ""), - timeout: Config.get([:suggestions, :timeout], 5000), - limit: Config.get([:suggestions, :limit], 23), - web: Config.get([:suggestions, :web], "") + enabled: false }, staffAccounts: staff_accounts, federation: federation_response, -- cgit v1.2.3 From 52e08ec9fdbfa780f24b19afd2533fb83a55d586 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 28 Jan 2020 03:52:35 +0300 Subject: explicitly describe perform op in AttachmentsClenupWorker --- lib/pleroma/workers/attachments_cleanup_worker.ex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index 595001ccb..23720ec56 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -12,7 +12,10 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do @impl Oban.Worker def perform( - %{"object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}}}, + %{ + "op" => "cleanup_attachments", + "object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}} + } = data, _job ) do hrefs = @@ -84,5 +87,5 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do |> Repo.delete_all() end - def perform(%{"object" => _object}, _job), do: :ok + def perform(%{"op" => "cleanup_attachments", "object" => _object}, _job), do: :ok end -- cgit v1.2.3 From eb4870e1cdc0b7f02c071b88a62cb76401393c0b Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 28 Jan 2020 03:54:54 +0300 Subject: Remove unused var --- lib/pleroma/workers/attachments_cleanup_worker.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index 23720ec56..a738df90a 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do %{ "op" => "cleanup_attachments", "object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}} - } = data, + }, _job ) do hrefs = -- cgit v1.2.3 From 02c3dd2e3d52a636c0fa13e8791da5d3cfe18707 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 28 Jan 2020 10:43:47 +0300 Subject: update ecto --- lib/pleroma/user.ex | 2 +- lib/pleroma/user_relationship.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3899c34c2..3c86cdb38 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1512,7 +1512,7 @@ defmodule Pleroma.User do data |> Map.put(:name, blank?(data[:name]) || data[:nickname]) |> remote_user_creation() - |> Repo.insert(on_conflict: :replace_all_except_primary_key, conflict_target: :nickname) + |> Repo.insert(on_conflict: {:replace_all_except, [:id]}, conflict_target: :nickname) |> set_cache() end diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex index 24c724549..3149e10e9 100644 --- a/lib/pleroma/user_relationship.ex +++ b/lib/pleroma/user_relationship.ex @@ -58,7 +58,7 @@ defmodule Pleroma.UserRelationship do target_id: target.id }) |> Repo.insert( - on_conflict: :replace_all_except_primary_key, + on_conflict: {:replace_all_except, [:id]}, conflict_target: [:source_id, :relationship_type, :target_id] ) end -- cgit v1.2.3 From 7f78bd7e376b3f1c9d6bbf1420d7c324b4508beb Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 28 Jan 2020 16:38:44 +0300 Subject: Fix __MODULE__ usage --- lib/pleroma/workers/attachments_cleanup_worker.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index a738df90a..ce6998a54 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -73,7 +73,7 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do _ -> "" end - base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url()) + base_url = Pleroma.Config.get([Pleroma.Upload, :base_url], Pleroma.Web.base_url()) file_path = String.trim_leading(href, "#{base_url}/#{prefix}") -- cgit v1.2.3 From e3fae3380e2af0978436191127b148923f62ae53 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 28 Jan 2020 13:38:49 +0000 Subject: Apply suggestion to lib/pleroma/web/feed/tag_controller.ex --- lib/pleroma/web/feed/tag_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex index 9b722336c..9accd0872 100644 --- a/lib/pleroma/web/feed/tag_controller.ex +++ b/lib/pleroma/web/feed/tag_controller.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.Feed.TagController do {format, tag} = parse_tag(raw_tag) activities = - %{"type" => ["Create"], "whole_db" => true, "tag" => tag} + %{"type" => ["Create"], "tag" => tag} |> put_in_if_exist("max_id", params["max_id"]) |> ActivityPub.fetch_public_activities() -- cgit v1.2.3 From 46915207b6ae6bfc6f245edb77c47033c81ecc4f Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 28 Jan 2020 14:40:40 +0100 Subject: Remove `whole_db` parameter everywhere, it's not used anymore --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 --- lib/pleroma/web/feed/feed_controller.ex | 1 - 2 files changed, 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 2e9d56ee5..1ac67b618 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -728,7 +728,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do params |> Map.put("user", reading_user) |> Map.put("actor_id", user.ap_id) - |> Map.put("whole_db", true) recipients = user_activities_recipients(%{ @@ -746,7 +745,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Map.put("type", ["Create", "Announce"]) |> Map.put("user", reading_user) |> Map.put("actor_id", user.ap_id) - |> Map.put("whole_db", true) |> Map.put("pinned_activity_ids", user.pinned_activities) params = @@ -773,7 +771,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do params |> Map.put("type", ["Create", "Announce"]) |> Map.put("instance", params["instance"]) - |> Map.put("whole_db", true) fetch_activities([Pleroma.Constants.as_public()], params, :offset) |> Enum.reverse() diff --git a/lib/pleroma/web/feed/feed_controller.ex b/lib/pleroma/web/feed/feed_controller.ex index d0e23007d..acc0c3e6c 100644 --- a/lib/pleroma/web/feed/feed_controller.ex +++ b/lib/pleroma/web/feed/feed_controller.ex @@ -36,7 +36,6 @@ defmodule Pleroma.Web.Feed.FeedController do activities = %{ "type" => ["Create"], - "whole_db" => true, "actor_id" => user.ap_id } |> Map.merge(Map.take(params, ["max_id"])) -- cgit v1.2.3 From dea968463de1139f0d6b6ff59298b1920f58f2f3 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 28 Jan 2020 16:52:20 +0300 Subject: Add logging --- lib/pleroma/workers/attachments_cleanup_worker.ex | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index ce6998a54..c6a033e9c 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -8,6 +8,8 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do alias Pleroma.Object alias Pleroma.Repo + require Logger + use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup" @impl Oban.Worker @@ -77,6 +79,7 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do file_path = String.trim_leading(href, "#{base_url}/#{prefix}") + Logger.warn("Deleting file #{file_path} (orig: #{href}, base_url: #{base_url})") uploader.delete_file(file_path) end -- cgit v1.2.3 From 804a702f97e7294feb3d4bdb527a461c40c05d80 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 28 Jan 2020 17:07:46 +0300 Subject: Fix base_url string trimming --- lib/pleroma/workers/attachments_cleanup_worker.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index c6a033e9c..4f7a1a193 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -75,7 +75,11 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do _ -> "" end - base_url = Pleroma.Config.get([Pleroma.Upload, :base_url], Pleroma.Web.base_url()) + base_url = + String.trim_trailing( + Pleroma.Config.get([Pleroma.Upload, :base_url], Pleroma.Web.base_url()), + "/" + ) file_path = String.trim_leading(href, "#{base_url}/#{prefix}") -- cgit v1.2.3 From d18a2e4e360bd6e630101a7dd2f4ae0902ac43a1 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 28 Jan 2020 17:22:24 +0300 Subject: Add test for custom base_url when deleting an attachment --- lib/pleroma/workers/attachments_cleanup_worker.ex | 3 --- 1 file changed, 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index 4f7a1a193..2cbc6b64d 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -8,8 +8,6 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do alias Pleroma.Object alias Pleroma.Repo - require Logger - use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup" @impl Oban.Worker @@ -83,7 +81,6 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do file_path = String.trim_leading(href, "#{base_url}/#{prefix}") - Logger.warn("Deleting file #{file_path} (orig: #{href}, base_url: #{base_url})") uploader.delete_file(file_path) end -- cgit v1.2.3 From 77f24525ca6636f5fb0b3864c346be683566efd3 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 28 Jan 2020 16:40:44 +0100 Subject: Streamer: Correctly handle reblog mutes --- lib/pleroma/web/streamer/worker.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex index a1b445f2f..5392c1ec3 100644 --- a/lib/pleroma/web/streamer/worker.ex +++ b/lib/pleroma/web/streamer/worker.ex @@ -138,7 +138,8 @@ defmodule Pleroma.Web.Streamer.Worker do with parent <- Object.normalize(item) || item, true <- - Enum.all?([blocked_ap_ids, muted_ap_ids, reblog_muted_ap_ids], &(item.actor not in &1)), + Enum.all?([blocked_ap_ids, muted_ap_ids], &(item.actor not in &1)), + true <- item.data["type"] != "Announce" || item.actor not in reblog_muted_ap_ids, true <- Enum.all?([blocked_ap_ids, muted_ap_ids], &(parent.data["actor"] not in &1)), true <- MapSet.disjoint?(recipients, recipient_blocks), %{host: item_host} <- URI.parse(item.actor), -- cgit v1.2.3 From 4eb935be78eeaf1decb7fc109cec09ca18d82854 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 20 Jan 2020 13:23:21 +0100 Subject: Create pleroma.email mix task Closes: https://git.pleroma.social/pleroma/pleroma/issues/1061 --- lib/mix/tasks/pleroma/email.ex | 25 +++++++++++++++++++++++++ lib/pleroma/emails/admin_email.ex | 14 ++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 lib/mix/tasks/pleroma/email.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/email.ex b/lib/mix/tasks/pleroma/email.ex new file mode 100644 index 000000000..2c3801429 --- /dev/null +++ b/lib/mix/tasks/pleroma/email.ex @@ -0,0 +1,25 @@ +defmodule Mix.Tasks.Pleroma.Email do + use Mix.Task + + @shortdoc "Simple Email test" + @moduledoc File.read!("docs/administration/CLI_tasks/email.md") + + def run(["test" | args]) do + Mix.Pleroma.start_pleroma() + + {options, [], []} = + OptionParser.parse( + args, + strict: [ + to: :string + ] + ) + + email = Pleroma.Emails.AdminEmail.test_email(options[:to]) + {:ok, _} = Pleroma.Emails.Mailer.deliver(email) + + Mix.shell().info( + "Test email has been sent to #{inspect(email.to)} from #{inspect(email.from)}" + ) + end +end diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index b15e4041b..b3623d3e4 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Emails.AdminEmail do import Swoosh.Email + alias Pleroma.Config alias Pleroma.Web.Router.Helpers defp instance_config, do: Pleroma.Config.get(:instance) @@ -20,6 +21,19 @@ defmodule Pleroma.Emails.AdminEmail do Helpers.feed_url(Pleroma.Web.Endpoint, :feed_redirect, user.id) end + def test_email(mail_to \\ nil) do + html_body = """ +

Instance Test Email

+

A test email was requested. Hello. :)

+ """ + + new() + |> to(mail_to || Config.get([:instance, :email])) + |> from({instance_name(), instance_notify_email()}) + |> subject("Instance Test Email") + |> html_body(html_body) + end + def report(to, reporter, account, statuses, comment) do comment_html = if comment do -- cgit v1.2.3 From 7bd4c1458103920479ea39a5334b54d729faae6e Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Tue, 28 Jan 2020 19:29:27 +0300 Subject: meta tag parser respect first title header --- lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex index 913975616..c2a3c07a2 100644 --- a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex +++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex @@ -48,6 +48,6 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do defp maybe_put_title(meta, _), do: meta defp get_page_title(html) do - Floki.find(html, "title") |> Floki.text() + Floki.find(html, "title") |> List.first() |> Floki.text() end end -- cgit v1.2.3 From 1f4fbe9d98b7daef7eef2ffffbaca00e1d20c52b Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Wed, 29 Jan 2020 11:13:34 +0300 Subject: title parse improvement --- lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex index c2a3c07a2..fae3c462e 100644 --- a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex +++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex @@ -48,6 +48,6 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do defp maybe_put_title(meta, _), do: meta defp get_page_title(html) do - Floki.find(html, "title") |> List.first() |> Floki.text() + Floki.find(html, "html head title") |> List.first() |> Floki.text() end end -- cgit v1.2.3