From 958b4cfde916c9be71d7412fe1c90750ec578fdc Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 24 Mar 2019 23:45:57 +0000 Subject: [PATCH 01/18] migrations: add function to see if a thread can be satisfied --- ...4222404_add_thread_visibility_function.exs | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 priv/repo/migrations/20190324222404_add_thread_visibility_function.exs diff --git a/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs b/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs new file mode 100644 index 000000000..cea0322e7 --- /dev/null +++ b/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs @@ -0,0 +1,76 @@ +defmodule Pleroma.Repo.Migrations.AddThreadVisibilityFunction do + use Ecto.Migration + @disable_ddl_transaction true + + def up do + statement = """ + CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar) RETURNS boolean AS $$ + DECLARE + public varchar := 'https://www.w3.org/ns/activitystreams#Public'; + child objects%ROWTYPE; + activity activities%ROWTYPE; + actor_user users%ROWTYPE; + author users%ROWTYPE; + author_fa varchar; + BEGIN + --- Fetch our actor. + SELECT * INTO actor_user FROM users WHERE users.ap_id = actor; + + --- Fetch our initial activity. + SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id; + + LOOP + --- Ensure that we have an activity before continuing. + IF activity IS NULL THEN + RETURN true; + END IF; + + --- Normalize the child object into child. + SELECT * INTO child FROM objects + INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id'; + + --- Fetch the author. + SELECT * INTO author FROM users WHERE users.ap_id = activity.actor; + + --- Prepare author's AS2 followers collection. + SELECT COALESCE(author.follower_address, '') INTO author_fa; + + --- Check visibility. + IF activity.actor = actor THEN + --- activity visible + NULL; + ELSIF ARRAY[public] && activity.recipients THEN + --- activity visible + NULL; + ELSIF ARRAY[author_fa] && activity.recipients AND ARRAY[author_fa] && actor_user.following THEN + --- activity visible + NULL; + ELSIF ARRAY[actor] && activity.recipients THEN + --- activity visible + NULL; + ELSE + --- activity not visible, break out of the loop + RETURN false; + END IF; + + --- If there's a parent, load it and do this all over again. + IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN + SELECT * INTO activity FROM activities + INNER JOIN objects ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE child.data->>'inReplyTo' = objects.data->>'id'; + ELSE + RETURN true; + END IF; + END LOOP; + END; + $$ LANGUAGE plpgsql IMMUTABLE; + """ + + execute(statement) + end + + def down do + execute("drop function thread_visibility(actor varchar, activity_id varchar)") + end +end From 0387f5213805cdc4e0bf86f98797cefcd03ba61d Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 00:06:02 +0000 Subject: [PATCH 02/18] activitypub: add restrict_thread_visibility() --- lib/pleroma/web/activity_pub/activity_pub.ex | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 233fee4fa..fec1bcd3e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -569,6 +569,20 @@ defp restrict_visibility(_query, %{visibility: visibility}) defp restrict_visibility(query, _visibility), do: query + defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}) do + query = + from( + a in query, + where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) + ) + + Ecto.Adapters.SQL.to_sql(:all, Repo, query) + + query + end + + defp restrict_thread_visibility(query, _), do: query + def fetch_user_activities(user, reading_user, params \\ %{}) do params = params @@ -848,6 +862,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_muted(opts) |> restrict_media(opts) |> restrict_visibility(opts) + |> restrict_thread_visibility(opts) |> restrict_replies(opts) |> restrict_reblogs(opts) |> restrict_pinned(opts) From de114ffbb0f92d24fd370adaaf43ff301ab04b4b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 00:10:20 +0000 Subject: [PATCH 03/18] activitypub: remove contain_timeline() --- lib/pleroma/web/activity_pub/activity_pub.ex | 8 -------- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 1 - lib/pleroma/web/twitter_api/twitter_api_controller.ex | 4 +--- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index fec1bcd3e..e544d0c50 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -980,12 +980,4 @@ def contain_broken_threads(%Activity{} = activity, %User{} = user) do def contain_activity(%Activity{} = activity, %User{} = user) do contain_broken_threads(activity, user) end - - # do post-processing on a timeline - def contain_timeline(timeline, user) do - timeline - |> Enum.filter(fn activity -> - contain_activity(activity, user) - end) - end end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 87e597074..66056a846 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -303,7 +303,6 @@ def home_timeline(%{assigns: %{user: user}} = conn, params) do activities = [user.ap_id | user.following] |> ActivityPub.fetch_activities(params) - |> ActivityPub.contain_timeline(user) |> Enum.reverse() conn diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 3c5a70be9..31e86685a 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -101,9 +101,7 @@ def friends_timeline(%{assigns: %{user: user}} = conn, params) do |> Map.put("blocking_user", user) |> Map.put("user", user) - activities = - ActivityPub.fetch_activities([user.ap_id | user.following], params) - |> ActivityPub.contain_timeline(user) + activities = ActivityPub.fetch_activities([user.ap_id | user.following], params) conn |> put_view(ActivityView) From 31db31c5879a2dedcc8dd4c671c4c9a79656355a Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 00:38:28 +0000 Subject: [PATCH 04/18] activitypub: visibility: use SQL thread_visibility() function instead of manually walking the thread --- lib/pleroma/web/activity_pub/visibility.ex | 26 +++++++--------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index b38ee0442..46dd46575 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -1,6 +1,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do alias Pleroma.Activity alias Pleroma.Object + alias Pleroma.Repo alias Pleroma.User def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false @@ -38,25 +39,14 @@ def visible_for_user?(activity, user) do visible_for_user?(activity, nil) || Enum.any?(x, &(&1 in y)) end - # guard - def entire_thread_visible_for_user?(nil, _user), do: false + def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do + {:ok, %{rows: [[result]]}} = + Ecto.Adapters.SQL.query(Repo, "SELECT thread_visibility($1, $2)", [ + user.ap_id, + activity.data["id"] + ]) - # XXX: Probably even more inefficient than the previous implementation intended to be a placeholder untill https://git.pleroma.social/pleroma/pleroma/merge_requests/971 is in develop - # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength - - def entire_thread_visible_for_user?( - %Activity{} = tail, - # %Activity{data: %{"object" => %{"inReplyTo" => parent_id}}} = tail, - user - ) do - case Object.normalize(tail) do - %{data: %{"inReplyTo" => parent_id}} when is_binary(parent_id) -> - parent = Activity.get_in_reply_to_activity(tail) - visible_for_user?(tail, user) && entire_thread_visible_for_user?(parent, user) - - _ -> - visible_for_user?(tail, user) - end + result end def get_visibility(object) do From c7644313e72520a371e4bd417b1ff852365849b6 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 01:23:15 +0000 Subject: [PATCH 05/18] test: update obsolete test --- test/web/activity_pub/activity_pub_test.exs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 0f90aa1ac..b41f6ab81 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -968,7 +968,8 @@ test "it filters broken threads" do assert length(activities) == 3 - activities = ActivityPub.contain_timeline(activities, user1) + activities = + ActivityPub.fetch_activities([user1.ap_id | user1.following], %{"user" => user1}) assert [public_activity, private_activity_1] == activities assert length(activities) == 2 From 75ce6adcffd2dbbc2ca2f83d7fe2d7fd659cd2f4 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 02:56:13 +0000 Subject: [PATCH 06/18] migration: only care about Create activities --- .../20190324222404_add_thread_visibility_function.exs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs b/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs index cea0322e7..11aa47e83 100644 --- a/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs +++ b/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs @@ -25,6 +25,11 @@ def up do RETURN true; END IF; + --- We only care about Create activities. + IF activity.data->>'type' != 'Create' THEN + RETURN true; + END IF; + --- Normalize the child object into child. SELECT * INTO child FROM objects INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' From 0aada88b5594b6714b8d65f8bee9c325d77d6e7b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 8 May 2019 23:17:51 +0000 Subject: [PATCH 07/18] bbs: chase timeline containment patch --- lib/pleroma/bbs/handler.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 106fe5d18..f34be961f 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -95,7 +95,6 @@ def handle_command(state, "home") do activities = [user.ap_id | user.following] |> ActivityPub.fetch_activities(params) - |> ActivityPub.contain_timeline(user) Enum.each(activities, fn activity -> puts_activity(activity) From 12f45e2a8907c74c6b65d866bc3bab547b31edfa Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 15 May 2019 16:22:52 +0000 Subject: [PATCH 08/18] update migration --- ...n.exs => 20190515222404_add_thread_visibility_function.exs} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename priv/repo/migrations/{20190324222404_add_thread_visibility_function.exs => 20190515222404_add_thread_visibility_function.exs} (97%) diff --git a/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs b/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs similarity index 97% rename from priv/repo/migrations/20190324222404_add_thread_visibility_function.exs rename to priv/repo/migrations/20190515222404_add_thread_visibility_function.exs index 11aa47e83..a3f717b89 100644 --- a/priv/repo/migrations/20190324222404_add_thread_visibility_function.exs +++ b/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs @@ -21,8 +21,9 @@ def up do LOOP --- Ensure that we have an activity before continuing. + --- If we don't, the thread is not satisfiable. IF activity IS NULL THEN - RETURN true; + RETURN false; END IF; --- We only care about Create activities. From f09c3afdf51eea17103d1445b31b7a269c474538 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 15 May 2019 16:23:01 +0000 Subject: [PATCH 09/18] chase test failures --- lib/pleroma/filter.ex | 3 ++- test/user_test.exs | 2 -- test/web/activity_pub/activity_pub_test.exs | 9 ++++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex index 79efc29f0..90457dadf 100644 --- a/lib/pleroma/filter.ex +++ b/lib/pleroma/filter.ex @@ -38,7 +38,8 @@ def get_filters(%User{id: user_id} = _user) do query = from( f in Pleroma.Filter, - where: f.user_id == ^user_id + where: f.user_id == ^user_id, + order_by: [desc: :id] ) Repo.all(query) diff --git a/test/user_test.exs b/test/user_test.exs index 0b65e89e9..bb47b4958 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -873,7 +873,6 @@ test "hide a user's statuses from timelines and notifications" do assert [activity] == ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2}) - |> ActivityPub.contain_timeline(user2) {:ok, _user} = User.deactivate(user) @@ -882,7 +881,6 @@ test "hide a user's statuses from timelines and notifications" do assert [] == ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2}) - |> ActivityPub.contain_timeline(user2) end end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index b41f6ab81..34e23b852 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -960,18 +960,21 @@ test "it filters broken threads" do "in_reply_to_status_id" => private_activity_2.id }) - activities = ActivityPub.fetch_activities([user1.ap_id | user1.following]) + activities = + ActivityPub.fetch_activities([user1.ap_id | user1.following]) + |> Enum.map(fn a -> a.id end) private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"]) - assert [public_activity, private_activity_1, private_activity_3] == activities + assert [public_activity.id, private_activity_1.id, private_activity_3.id] == activities assert length(activities) == 3 activities = ActivityPub.fetch_activities([user1.ap_id | user1.following], %{"user" => user1}) + |> Enum.map(fn a -> a.id end) - assert [public_activity, private_activity_1] == activities + assert [public_activity.id, private_activity_1.id] == activities assert length(activities) == 2 end end From 71fa7eeb6fdc7cf2087a32fb515ad11b7bf90c01 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 15 May 2019 16:54:14 +0000 Subject: [PATCH 10/18] thread visibility function: significantly improve efficiency --- ...5222404_add_thread_visibility_function.exs | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs b/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs index a3f717b89..a4daf680b 100644 --- a/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs +++ b/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs @@ -10,8 +10,8 @@ def up do child objects%ROWTYPE; activity activities%ROWTYPE; actor_user users%ROWTYPE; - author users%ROWTYPE; author_fa varchar; + valid_recipients varchar[]; BEGIN --- Fetch our actor. SELECT * INTO actor_user FROM users WHERE users.ap_id = actor; @@ -36,26 +36,17 @@ def up do INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id'; - --- Fetch the author. - SELECT * INTO author FROM users WHERE users.ap_id = activity.actor; + --- Fetch the author's AS2 following collection. + SELECT COALESCE(author.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor; - --- Prepare author's AS2 followers collection. - SELECT COALESCE(author.follower_address, '') INTO author_fa; + --- Prepare valid recipients array. + valid_recipients := ARRAY[actor, public]; + IF ARRAY[author_fa] && actor_user.following THEN + valid_recipients := valid_recipients || author_fa; + END IF; --- Check visibility. - IF activity.actor = actor THEN - --- activity visible - NULL; - ELSIF ARRAY[public] && activity.recipients THEN - --- activity visible - NULL; - ELSIF ARRAY[author_fa] && activity.recipients AND ARRAY[author_fa] && actor_user.following THEN - --- activity visible - NULL; - ELSIF ARRAY[actor] && activity.recipients THEN - --- activity visible - NULL; - ELSE + IF NOT valid_recipients && activity.recipients THEN --- activity not visible, break out of the loop RETURN false; END IF; From a591ab6112abdf162f4d6fdfbbcdd85bbaf75058 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 15 May 2019 16:56:46 +0000 Subject: [PATCH 11/18] activity pub: remove Ecto SQL query dumps --- lib/pleroma/web/activity_pub/activity_pub.ex | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e544d0c50..7cd5b889b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -540,8 +540,6 @@ defp restrict_visibility(query, %{visibility: visibility}) ) ) - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - query else Logger.error("Could not restrict visibility to #{visibility}") @@ -557,8 +555,6 @@ defp restrict_visibility(query, %{visibility: visibility}) fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) ) - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - query end @@ -576,8 +572,6 @@ defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}) do where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) ) - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - query end From f3971cbde3d69faec973717e1421f4a643ef947e Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 15 May 2019 17:02:40 +0000 Subject: [PATCH 12/18] thread visibility function: fix use of no longer used author variable --- .../20190515222404_add_thread_visibility_function.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs b/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs index a4daf680b..dc9abc998 100644 --- a/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs +++ b/priv/repo/migrations/20190515222404_add_thread_visibility_function.exs @@ -37,7 +37,7 @@ def up do WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id'; --- Fetch the author's AS2 following collection. - SELECT COALESCE(author.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor; + SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor; --- Prepare valid recipients array. valid_recipients := ARRAY[actor, public]; From 0ae15c23061413cb2b67d2be462742dccae01fb4 Mon Sep 17 00:00:00 2001 From: PolymerWitch Date: Wed, 15 May 2019 15:36:20 -0700 Subject: [PATCH 13/18] Added package to dependency list Added the erlang-ssh package to the dependency list and the installation command instructions. The project wouldn't build otherwise. --- docs/installation/debian_based_en.md | 3 ++- docs/installation/debian_based_jp.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/installation/debian_based_en.md b/docs/installation/debian_based_en.md index 9613a329b..9c0ef92d4 100644 --- a/docs/installation/debian_based_en.md +++ b/docs/installation/debian_based_en.md @@ -12,6 +12,7 @@ This guide will assume you are on Debian Stretch. This guide should also work wi * `erlang-tools` * `erlang-parsetools` * `erlang-eldap`, if you want to enable ldap authenticator +* `erlang-ssh` * `erlang-xmerl` * `git` * `build-essential` @@ -49,7 +50,7 @@ sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb ```shell sudo apt update -sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools +sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh ``` ### Install PleromaBE diff --git a/docs/installation/debian_based_jp.md b/docs/installation/debian_based_jp.md index ac5dcaaee..41cce6792 100644 --- a/docs/installation/debian_based_jp.md +++ b/docs/installation/debian_based_jp.md @@ -14,6 +14,7 @@ - erlang-dev - erlang-tools - erlang-parsetools +- erlang-ssh - erlang-xmerl (Jessieではバックポートからインストールすること!) - git - build-essential @@ -44,7 +45,7 @@ wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb * ElixirとErlangをインストールします、 ``` -apt update && apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools +apt update && apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh ``` ### Pleroma BE (バックエンド) をインストールします From 1d2923e5d0893b39f41ded77d24652029f6f12ec Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Thu, 16 May 2019 01:36:26 +0300 Subject: [PATCH 14/18] Update tag/untag docs --- docs/api/admin_api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 75fa2ee83..8f79d7f24 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -106,14 +106,14 @@ Authentication is required and the user must be an admin. - Method: `PUT` - Params: - - `nickname` + - `nicknames` - `tags` ### Untag a list of users - Method: `DELETE` - Params: - - `nickname` + - `nicknames` - `tags` ## `/api/pleroma/admin/users/:nickname/permission_group` From 0641e685c166859fe2d5994bfcd069e0a8e62acf Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Thu, 16 May 2019 01:46:43 +0300 Subject: [PATCH 15/18] Note that nicknames is an array --- docs/api/admin_api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 8f79d7f24..94fce9c6f 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -106,14 +106,14 @@ Authentication is required and the user must be an admin. - Method: `PUT` - Params: - - `nicknames` + - `nicknames` (array) - `tags` ### Untag a list of users - Method: `DELETE` - Params: - - `nicknames` + - `nicknames` (array) - `tags` ## `/api/pleroma/admin/users/:nickname/permission_group` From 107c83ab2b186c951dc27140908d414a202119d8 Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Thu, 16 May 2019 01:48:53 +0300 Subject: [PATCH 16/18] Note that nicknames is an array --- docs/api/admin_api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 94fce9c6f..59578f8d1 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -107,14 +107,14 @@ Authentication is required and the user must be an admin. - Method: `PUT` - Params: - `nicknames` (array) - - `tags` + - `tags` (array) ### Untag a list of users - Method: `DELETE` - Params: - `nicknames` (array) - - `tags` + - `tags` (array) ## `/api/pleroma/admin/users/:nickname/permission_group` From c31026423c8c73ab33dc0d38b9d187a0d2b68309 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Thu, 16 May 2019 04:41:27 +0000 Subject: [PATCH 17/18] publisher: use the correct queue name for outgoing federation --- lib/pleroma/web/federator/publisher.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 916bcdcba..fb4e8548d 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.Federator.Publisher do """ @spec enqueue_one(module(), Map.t()) :: :ok def enqueue_one(module, %{} = params), - do: PleromaJobQueue.enqueue(:federation_outgoing, __MODULE__, [:publish_one, module, params]) + do: PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_one, module, params]) @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()} def perform(:publish_one, module, params) do From 73ae58fdfaf0b9dc9630929b0b84ae3b6083684a Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 16 May 2019 13:23:41 +0000 Subject: [PATCH 18/18] Feature/896 toggling confirmation --- CHANGELOG.md | 3 ++- lib/mix/tasks/pleroma/user.ex | 19 +++++++++++++++++++ lib/pleroma/user.ex | 13 +++++++++++++ lib/pleroma/user/info.ex | 2 +- test/tasks/user_test.exs | 27 +++++++++++++++++++++++++++ test/user_test.exs | 18 ++++++++++++++++++ 6 files changed, 80 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0e849285..b3d8e1e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - [Prometheus](https://prometheus.io/) metrics - Support for Mastodon's remote interaction - Mix Tasks: `mix pleroma.database remove_embedded_objects` +- Mix Tasks: `mix pleroma.user toggle_confirmed` - Federation: Support for reports - Configuration: `safe_dm_mentions` option - Configuration: `link_name` option @@ -98,7 +99,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Make `irreversible` field default to `false` [`POST /api/v1/filters`] ## Removed -- Configuration: `config :pleroma, :fe` in favor of the more flexible `config :pleroma, :frontend_configurations` +- Configuration: `config :pleroma, :fe` in favor of the more flexible `config :pleroma, :frontend_configurations` ## [0.9.9999] - 2019-04-05 ### Security diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index d130ff8c9..25fc40ea7 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -77,6 +77,10 @@ defmodule Mix.Tasks.Pleroma.User do ## Delete tags from a user. mix pleroma.user untag NICKNAME TAGS + + ## Toggle confirmation of the user's account. + + mix pleroma.user toggle_confirmed NICKNAME """ def run(["new", nickname, email | rest]) do {options, [], []} = @@ -388,6 +392,21 @@ def run(["delete_activities", nickname]) do end end + def run(["toggle_confirmed", nickname]) do + Common.start_pleroma() + + with %User{} = user <- User.get_cached_by_nickname(nickname) do + {:ok, user} = User.toggle_confirmation(user) + + message = if user.info.confirmation_pending, do: "needs", else: "doesn't need" + + Mix.shell().info("#{nickname} #{message} confirmation.") + else + _ -> + Mix.shell().error("No local user #{nickname}") + end + end + defp set_moderator(user, value) do info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value}) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c6a562a61..1aa966dfc 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1378,4 +1378,17 @@ def all_superusers do def showing_reblogs?(%User{} = user, %User{} = target) do target.ap_id not in user.info.muted_reblogs end + + @spec toggle_confirmation(User.t()) :: {:ok, User.t()} | {:error, Changeset.t()} + def toggle_confirmation(%User{} = user) do + need_confirmation? = !user.info.confirmation_pending + + info_changeset = + User.Info.confirmation_changeset(user.info, need_confirmation: need_confirmation?) + + user + |> change() + |> put_embed(:info, info_changeset) + |> update_and_set_cache() + end end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 5a50ee639..5f0cefc00 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -212,7 +212,7 @@ def profile_update(info, params) do ]) end - @spec confirmation_changeset(Info.t(), keyword()) :: Ecto.Changerset.t() + @spec confirmation_changeset(Info.t(), keyword()) :: Changeset.t() def confirmation_changeset(info, opts) do need_confirmation? = Keyword.get(opts, :need_confirmation) diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs index eaf4ecf84..1f97740be 100644 --- a/test/tasks/user_test.exs +++ b/test/tasks/user_test.exs @@ -338,4 +338,31 @@ test "activities are deleted" do assert message == "User #{nickname} statuses deleted." end end + + describe "running toggle_confirmed" do + test "user is confirmed" do + %{id: id, nickname: nickname} = insert(:user, info: %{confirmation_pending: false}) + + assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) + assert_received {:mix_shell, :info, [message]} + assert message == "#{nickname} needs confirmation." + + user = Repo.get(User, id) + assert user.info.confirmation_pending + assert user.info.confirmation_token + end + + test "user is not confirmed" do + %{id: id, nickname: nickname} = + insert(:user, info: %{confirmation_pending: true, confirmation_token: "some token"}) + + assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) + assert_received {:mix_shell, :info, [message]} + assert message == "#{nickname} doesn't need confirmation." + + user = Repo.get(User, id) + refute user.info.confirmation_pending + refute user.info.confirmation_token + end + end end diff --git a/test/user_test.exs b/test/user_test.exs index 0b65e89e9..f256396c0 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1204,4 +1204,22 @@ test "follower count is updated when a follower is blocked" do assert Map.get(user_show, "followers_count") == 2 end + + describe "toggle_confirmation/1" do + test "if user is confirmed" do + user = insert(:user, info: %{confirmation_pending: false}) + {:ok, user} = User.toggle_confirmation(user) + + assert user.info.confirmation_pending + assert user.info.confirmation_token + end + + test "if user is unconfirmed" do + user = insert(:user, info: %{confirmation_pending: true, confirmation_token: "some token"}) + {:ok, user} = User.toggle_confirmation(user) + + refute user.info.confirmation_pending + refute user.info.confirmation_token + end + end end