diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a30c8daed..af0e569a4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -21,6 +21,7 @@ defmodule Pleroma.User do field :avatar, :map field :local, :boolean, default: true field :info, :map, default: %{} + field :follower_address, :string timestamps() end @@ -58,7 +59,7 @@ def user_info(%User{} = user) do select: count(a.id) follower_count_query = from u in User, - where: fragment("? @> ?", u.following, ^User.ap_followers(user)), + where: fragment("? @> ?", u.following, ^user.follower_address), select: count(u.id) %{ @@ -70,7 +71,7 @@ def user_info(%User{} = user) do @email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ def remote_user_creation(params) do - %User{} + changes = %User{} |> cast(params, [:bio, :name, :ap_id, :nickname, :info, :avatar]) |> validate_required([:name, :ap_id, :nickname]) |> unique_constraint(:nickname) @@ -78,6 +79,13 @@ def remote_user_creation(params) do |> validate_length(:bio, max: 5000) |> validate_length(:name, max: 100) |> put_change(:local, false) + if changes.valid? do + followers = User.ap_followers(%User{nickname: changes.changes[:nickname]}) + changes + |> put_change(:follower_address, followers) + else + changes + end end def register_changeset(struct, params \\ %{}) do @@ -100,13 +108,14 @@ def register_changeset(struct, params \\ %{}) do |> put_change(:password_hash, hashed) |> put_change(:ap_id, ap_id) |> put_change(:following, [followers]) + |> put_change(:follower_address, followers) else changeset end end def follow(%User{} = follower, %User{} = followed) do - ap_followers = User.ap_followers(followed) + ap_followers = followed.follower_address if following?(follower, followed) do {:error, "Could not follow user: #{followed.nickname} is already on your list."} @@ -125,7 +134,7 @@ def follow(%User{} = follower, %User{} = followed) do end def unfollow(%User{} = follower, %User{} = followed) do - ap_followers = User.ap_followers(followed) + ap_followers = followed.follower_address if following?(follower, followed) do following = follower.following |> List.delete(ap_followers) @@ -140,7 +149,7 @@ def unfollow(%User{} = follower, %User{} = followed) do end def following?(%User{} = follower, %User{} = followed) do - Enum.member?(follower.following, User.ap_followers(followed)) + Enum.member?(follower.following, followed.follower_address) end def get_by_ap_id(ap_id) do diff --git a/priv/repo/migrations/20170719152213_add_follower_address_to_user.exs b/priv/repo/migrations/20170719152213_add_follower_address_to_user.exs new file mode 100644 index 000000000..bd3c93bd5 --- /dev/null +++ b/priv/repo/migrations/20170719152213_add_follower_address_to_user.exs @@ -0,0 +1,33 @@ +defmodule Pleroma.Repo.Migrations.AddFollowerAddressToUser do + use Ecto.Migration + import Ecto.Query + import Supervisor.Spec + alias Pleroma.{Repo, User} + + def up do + alter table(:users) do + add :follower_address, :string, unique: true + end + flush() + + children = [ + # Start the endpoint when the application starts + supervisor(Pleroma.Web.Endpoint, []) + ] + opts = [strategy: :one_for_one, name: Pleroma.Supervisor] + Supervisor.start_link(children, opts) + + Enum.each(Repo.all(User), fn (user) -> + if !user.follower_address do + cs = Ecto.Changeset.change(user, %{follower_address: User.ap_followers(user)}) + Repo.update!(cs) + end + end) + end + + def down do + alter table(:users) do + remove :follower_address + end + end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index bb3bdb02c..1356ebde9 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -9,7 +9,7 @@ def user_factory do password_hash: Comeonin.Pbkdf2.hashpwsalt("test"), bio: sequence(:bio, &"Tester Number #{&1}"), } - %{ user | ap_id: Pleroma.User.ap_id(user) } + %{ user | ap_id: Pleroma.User.ap_id(user), follower_address: Pleroma.User.ap_followers(user) } end def note_factory do diff --git a/test/user_test.exs b/test/user_test.exs index c79564385..0f42e9b51 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -103,6 +103,7 @@ test "it sets the password_hash, ap_id and following fields" do assert is_binary(changeset.changes[:password_hash]) assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname}) assert changeset.changes[:following] == [User.ap_followers(%User{nickname: @full_user_data.nickname})] + assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers" end end @@ -162,6 +163,12 @@ test "it confirms validity" do assert cs.valid? end + test "it sets the follower_adress" do + cs = User.remote_user_creation(@valid_remote) + # remote users get a fake local follower address + assert cs.changes.follower_address == User.ap_followers(%User{ nickname: @valid_remote[:nickname] }) + end + test "it enforces the fqn format for nicknames" do cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"}) assert cs.changes.local == false