Remove duplicated entries in users' following lists
This commit is contained in:
parent
0f8892686a
commit
2c303afc8b
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
|
- Support for Mastodon's remote interaction
|
||||||
- Mix Tasks: `mix pleroma.database bump_all_conversations`
|
- Mix Tasks: `mix pleroma.database bump_all_conversations`
|
||||||
- Mix Tasks: `mix pleroma.database remove_embedded_objects`
|
- 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`
|
- Mix Tasks: `mix pleroma.user toggle_confirmed`
|
||||||
- Federation: Support for reports
|
- Federation: Support for reports
|
||||||
- Configuration: `safe_dm_mentions` option
|
- Configuration: `safe_dm_mentions` option
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
defmodule Mix.Tasks.Pleroma.Database do
|
defmodule Mix.Tasks.Pleroma.Database do
|
||||||
alias Mix.Tasks.Pleroma.Common
|
alias Mix.Tasks.Pleroma.Common
|
||||||
alias Pleroma.Conversation
|
alias Pleroma.Conversation
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
require Logger
|
require Logger
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
|
|
||||||
|
@ -25,6 +27,9 @@ defmodule Mix.Tasks.Pleroma.Database do
|
||||||
|
|
||||||
mix pleroma.database bump_all_conversations
|
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
|
def run(["remove_embedded_objects" | args]) do
|
||||||
{options, [], []} =
|
{options, [], []} =
|
||||||
|
@ -38,7 +43,7 @@ def run(["remove_embedded_objects" | args]) do
|
||||||
Common.start_pleroma()
|
Common.start_pleroma()
|
||||||
Logger.info("Removing embedded objects")
|
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;",
|
"update activities set data = jsonb_set(data, '{object}'::text[], data->'object'->'id') where data->'object'->>'id' is not null;",
|
||||||
[],
|
[],
|
||||||
timeout: :infinity
|
timeout: :infinity
|
||||||
|
@ -47,7 +52,7 @@ def run(["remove_embedded_objects" | args]) do
|
||||||
if Keyword.get(options, :vacuum) do
|
if Keyword.get(options, :vacuum) do
|
||||||
Logger.info("Runnning VACUUM FULL")
|
Logger.info("Runnning VACUUM FULL")
|
||||||
|
|
||||||
Pleroma.Repo.query!(
|
Repo.query!(
|
||||||
"vacuum full;",
|
"vacuum full;",
|
||||||
[],
|
[],
|
||||||
timeout: :infinity
|
timeout: :infinity
|
||||||
|
@ -59,4 +64,12 @@ def run(["bump_all_conversations"]) do
|
||||||
Common.start_pleroma()
|
Common.start_pleroma()
|
||||||
Conversation.bump_for_all_activities()
|
Conversation.bump_for_all_activities()
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -166,7 +166,7 @@ def remote_user_creation(params) do
|
||||||
|
|
||||||
def update_changeset(struct, params \\ %{}) do
|
def update_changeset(struct, params \\ %{}) do
|
||||||
struct
|
struct
|
||||||
|> cast(params, [:bio, :name, :avatar])
|
|> cast(params, [:bio, :name, :avatar, :following])
|
||||||
|> unique_constraint(:nickname)
|
|> unique_constraint(:nickname)
|
||||||
|> validate_format(:nickname, local_nickname_regex())
|
|> validate_format(:nickname, local_nickname_regex())
|
||||||
|> validate_length(:bio, max: 5000)
|
|> validate_length(:bio, max: 5000)
|
||||||
|
@ -709,6 +709,18 @@ def update_follower_count(%User{} = user) do
|
||||||
end
|
end
|
||||||
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()]
|
@spec get_users_from_set([String.t()], boolean()) :: [User.t()]
|
||||||
def get_users_from_set(ap_ids, local_only \\ true) do
|
def get_users_from_set(ap_ids, local_only \\ true) do
|
||||||
criteria = %{ap_id: ap_ids, deactivated: false}
|
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
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.UserTest do
|
defmodule Mix.Tasks.Pleroma.UserTest do
|
||||||
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
|
|
@ -626,6 +626,37 @@ test "it sets the info->follower_count property" do
|
||||||
end
|
end
|
||||||
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
|
describe "follow_import" do
|
||||||
test "it imports user followings from list" do
|
test "it imports user followings from list" do
|
||||||
[user1, user2, user3] = insert_list(3, :user)
|
[user1, user2, user3] = insert_list(3, :user)
|
||||||
|
|
Loading…
Reference in a new issue