Merge branch 'feature/task-update-following' into 'develop'
Remove duplicated entries in users' following lists Closes #888 See merge request pleroma/pleroma!1166
This commit is contained in:
		
						commit
						a328251a52
					
				
					 6 changed files with 110 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 | 
			
		|||
- Support for Mastodon's remote interaction
 | 
			
		||||
- Mix Tasks: `mix pleroma.database bump_all_conversations`
 | 
			
		||||
- Mix Tasks: `mix pleroma.database remove_embedded_objects`
 | 
			
		||||
- Mix Tasks: `mix pleroma.database update_users_following_followers_counts`
 | 
			
		||||
- Mix Tasks: `mix pleroma.user toggle_confirmed`
 | 
			
		||||
- Federation: Support for reports
 | 
			
		||||
- Configuration: `safe_dm_mentions` option
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@
 | 
			
		|||
defmodule Mix.Tasks.Pleroma.Database do
 | 
			
		||||
  alias Mix.Tasks.Pleroma.Common
 | 
			
		||||
  alias Pleroma.Conversation
 | 
			
		||||
  alias Pleroma.Repo
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
  require Logger
 | 
			
		||||
  use Mix.Task
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -25,6 +27,9 @@ defmodule Mix.Tasks.Pleroma.Database do
 | 
			
		|||
 | 
			
		||||
      mix pleroma.database bump_all_conversations
 | 
			
		||||
 | 
			
		||||
  ## Remove duplicated items from following and update followers count for all users
 | 
			
		||||
 | 
			
		||||
      mix pleroma.database update_users_following_followers_counts
 | 
			
		||||
  """
 | 
			
		||||
  def run(["remove_embedded_objects" | args]) do
 | 
			
		||||
    {options, [], []} =
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +43,7 @@ def run(["remove_embedded_objects" | args]) do
 | 
			
		|||
    Common.start_pleroma()
 | 
			
		||||
    Logger.info("Removing embedded objects")
 | 
			
		||||
 | 
			
		||||
    Pleroma.Repo.query!(
 | 
			
		||||
    Repo.query!(
 | 
			
		||||
      "update activities set data = jsonb_set(data, '{object}'::text[], data->'object'->'id') where data->'object'->>'id' is not null;",
 | 
			
		||||
      [],
 | 
			
		||||
      timeout: :infinity
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +52,7 @@ def run(["remove_embedded_objects" | args]) do
 | 
			
		|||
    if Keyword.get(options, :vacuum) do
 | 
			
		||||
      Logger.info("Runnning VACUUM FULL")
 | 
			
		||||
 | 
			
		||||
      Pleroma.Repo.query!(
 | 
			
		||||
      Repo.query!(
 | 
			
		||||
        "vacuum full;",
 | 
			
		||||
        [],
 | 
			
		||||
        timeout: :infinity
 | 
			
		||||
| 
						 | 
				
			
			@ -59,4 +64,12 @@ def run(["bump_all_conversations"]) do
 | 
			
		|||
    Common.start_pleroma()
 | 
			
		||||
    Conversation.bump_for_all_activities()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def run(["update_users_following_followers_counts"]) do
 | 
			
		||||
    Common.start_pleroma()
 | 
			
		||||
 | 
			
		||||
    users = Repo.all(User)
 | 
			
		||||
    Enum.each(users, &User.remove_duplicated_following/1)
 | 
			
		||||
    Enum.each(users, &User.update_follower_count/1)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -166,7 +166,7 @@ def remote_user_creation(params) do
 | 
			
		|||
 | 
			
		||||
  def update_changeset(struct, params \\ %{}) do
 | 
			
		||||
    struct
 | 
			
		||||
    |> cast(params, [:bio, :name, :avatar])
 | 
			
		||||
    |> cast(params, [:bio, :name, :avatar, :following])
 | 
			
		||||
    |> unique_constraint(:nickname)
 | 
			
		||||
    |> validate_format(:nickname, local_nickname_regex())
 | 
			
		||||
    |> validate_length(:bio, max: 5000)
 | 
			
		||||
| 
						 | 
				
			
			@ -709,6 +709,18 @@ def update_follower_count(%User{} = user) do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def remove_duplicated_following(%User{following: following} = user) do
 | 
			
		||||
    uniq_following = Enum.uniq(following)
 | 
			
		||||
 | 
			
		||||
    if length(following) == length(uniq_following) do
 | 
			
		||||
      {:ok, user}
 | 
			
		||||
    else
 | 
			
		||||
      user
 | 
			
		||||
      |> update_changeset(%{following: uniq_following})
 | 
			
		||||
      |> update_and_set_cache()
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec get_users_from_set([String.t()], boolean()) :: [User.t()]
 | 
			
		||||
  def get_users_from_set(ap_ids, local_only \\ true) do
 | 
			
		||||
    criteria = %{ap_id: ap_ids, deactivated: false}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								test/tasks/database_test.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								test/tasks/database_test.exs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
# Pleroma: A lightweight social networking server
 | 
			
		||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 | 
			
		||||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 | 
			
		||||
defmodule Mix.Tasks.Pleroma.DatabaseTest do
 | 
			
		||||
  alias Pleroma.Repo
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
  use Pleroma.DataCase
 | 
			
		||||
 | 
			
		||||
  import Pleroma.Factory
 | 
			
		||||
 | 
			
		||||
  setup_all do
 | 
			
		||||
    Mix.shell(Mix.Shell.Process)
 | 
			
		||||
 | 
			
		||||
    on_exit(fn ->
 | 
			
		||||
      Mix.shell(Mix.Shell.IO)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    :ok
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "running update_users_following_followers_counts" do
 | 
			
		||||
    test "following and followers count are updated" do
 | 
			
		||||
      [user, user2] = insert_pair(:user)
 | 
			
		||||
      {:ok, %User{following: following, info: info} = user} = User.follow(user, user2)
 | 
			
		||||
 | 
			
		||||
      assert length(following) == 2
 | 
			
		||||
      assert info.follower_count == 0
 | 
			
		||||
 | 
			
		||||
      info_cng = Ecto.Changeset.change(info, %{follower_count: 3})
 | 
			
		||||
 | 
			
		||||
      {:ok, user} =
 | 
			
		||||
        user
 | 
			
		||||
        |> Ecto.Changeset.change(%{following: following ++ following})
 | 
			
		||||
        |> Ecto.Changeset.put_embed(:info, info_cng)
 | 
			
		||||
        |> Repo.update()
 | 
			
		||||
 | 
			
		||||
      assert length(user.following) == 4
 | 
			
		||||
      assert user.info.follower_count == 3
 | 
			
		||||
 | 
			
		||||
      assert :ok == Mix.Tasks.Pleroma.Database.run(["update_users_following_followers_counts"])
 | 
			
		||||
 | 
			
		||||
      user = User.get_by_id(user.id)
 | 
			
		||||
 | 
			
		||||
      assert length(user.following) == 2
 | 
			
		||||
      assert user.info.follower_count == 0
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -3,6 +3,7 @@
 | 
			
		|||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 | 
			
		||||
defmodule Mix.Tasks.Pleroma.UserTest do
 | 
			
		||||
  alias Pleroma.Repo
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
  use Pleroma.DataCase
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -626,6 +626,37 @@ test "it sets the info->follower_count property" do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "remove duplicates from following list" do
 | 
			
		||||
    test "it removes duplicates" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      follower = insert(:user)
 | 
			
		||||
 | 
			
		||||
      {:ok, %User{following: following} = follower} = User.follow(follower, user)
 | 
			
		||||
      assert length(following) == 2
 | 
			
		||||
 | 
			
		||||
      {:ok, follower} =
 | 
			
		||||
        follower
 | 
			
		||||
        |> User.update_changeset(%{following: following ++ following})
 | 
			
		||||
        |> Repo.update()
 | 
			
		||||
 | 
			
		||||
      assert length(follower.following) == 4
 | 
			
		||||
 | 
			
		||||
      {:ok, follower} = User.remove_duplicated_following(follower)
 | 
			
		||||
      assert length(follower.following) == 2
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it does nothing when following is uniq" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      follower = insert(:user)
 | 
			
		||||
 | 
			
		||||
      {:ok, follower} = User.follow(follower, user)
 | 
			
		||||
      assert length(follower.following) == 2
 | 
			
		||||
 | 
			
		||||
      {:ok, follower} = User.remove_duplicated_following(follower)
 | 
			
		||||
      assert length(follower.following) == 2
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "follow_import" do
 | 
			
		||||
    test "it imports user followings from list" do
 | 
			
		||||
      [user1, user2, user3] = insert_list(3, :user)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue