user_test.exs 12.9 KB
Newer Older
lain's avatar
lain committed
1 2
defmodule Pleroma.UserTest do
  alias Pleroma.Builders.UserBuilder
lain's avatar
lain committed
3
  alias Pleroma.{User, Repo, Activity}
lain's avatar
lain committed
4 5
  alias Pleroma.Web.OStatus
  alias Pleroma.Web.Websub.WebsubClientSubscription
6
  alias Pleroma.Web.CommonAPI
lain's avatar
lain committed
7 8
  use Pleroma.DataCase

lain's avatar
lain committed
9
  import Pleroma.Factory
lain's avatar
lain committed
10
  import Ecto.Query
lain's avatar
lain committed
11

lain's avatar
lain committed
12
  test "ap_id returns the activity pub id for the user" do
lain's avatar
lain committed
13
    user = UserBuilder.build()
lain's avatar
lain committed
14

lain's avatar
lain committed
15
    expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
lain's avatar
lain committed
16 17 18 19 20

    assert expected_ap_id == User.ap_id(user)
  end

  test "ap_followers returns the followers collection for the user" do
lain's avatar
lain committed
21
    user = UserBuilder.build()
lain's avatar
lain committed
22 23 24 25 26

    expected_followers_collection = "#{User.ap_id(user)}/followers"

    assert expected_followers_collection == User.ap_followers(user)
  end
lain's avatar
lain committed
27

lain's avatar
lain committed
28
  test "follow takes a user and another user" do
lain's avatar
lain committed
29 30
    user = insert(:user)
    followed = insert(:user)
lain's avatar
lain committed
31

lain's avatar
lain committed
32
    {:ok, user} = User.follow(user, followed)
lain's avatar
lain committed
33 34 35

    user = Repo.get(User, user.id)

36 37 38
    followed = User.get_by_ap_id(followed.ap_id)
    assert followed.info["follower_count"] == 1

39
    assert User.ap_followers(followed) in user.following
lain's avatar
lain committed
40
  end
lain's avatar
lain committed
41

lain's avatar
lain committed
42 43 44 45 46 47 48
  test "can't follow a deactivated users" do
    user = insert(:user)
    followed = insert(:user, info: %{"deactivated" => true})

    {:error, _} = User.follow(user, followed)
  end

49 50 51 52 53 54 55 56 57
  test "can't follow a user who blocked us" do
    blocker = insert(:user)
    blockee = insert(:user)

    {:ok, blocker} = User.block(blocker, blockee)

    {:error, _} = User.follow(blockee, blocker)
  end

lain's avatar
lain committed
58 59 60 61
  # This is a somewhat useless test.
  # test "following a remote user will ensure a websub subscription is present" do
  #   user = insert(:user)
  #   {:ok, followed} = OStatus.make_user("shp@social.heldscal.la")
lain's avatar
lain committed
62

lain's avatar
lain committed
63
  #   assert followed.local == false
lain's avatar
lain committed
64

lain's avatar
lain committed
65 66
  #   {:ok, user} = User.follow(user, followed)
  #   assert User.ap_followers(followed) in user.following
lain's avatar
lain committed
67

lain's avatar
lain committed
68 69 70
  #   query = from w in WebsubClientSubscription,
  #   where: w.topic == ^followed.info["topic"]
  #   websub = Repo.one(query)
lain's avatar
lain committed
71

lain's avatar
lain committed
72 73
  #   assert websub
  # end
lain's avatar
lain committed
74

lain's avatar
lain committed
75
  test "unfollow takes a user and another user" do
lain's avatar
lain committed
76 77
    followed = insert(:user)
    user = insert(:user, %{following: [User.ap_followers(followed)]})
lain's avatar
lain committed
78

lain's avatar
lain committed
79
    {:ok, user, _activity} = User.unfollow(user, followed)
lain's avatar
lain committed
80 81 82 83 84

    user = Repo.get(User, user.id)

    assert user.following == []
  end
85

86 87 88 89 90
  test "unfollow doesn't unfollow yourself" do
    user = insert(:user)

    {:error, _} = User.unfollow(user, user)

eal's avatar
eal committed
91
    user = Repo.get(User, user.id)
92 93 94
    assert user.following == [user.ap_id]
  end

95
  test "test if a user is following another user" do
lain's avatar
lain committed
96 97
    followed = insert(:user)
    user = insert(:user, %{following: [User.ap_followers(followed)]})
98 99 100 101

    assert User.following?(user, followed)
    refute User.following?(followed, user)
  end
lain's avatar
lain committed
102 103 104 105 106 107 108 109 110 111 112

  describe "user registration" do
    @full_user_data %{
      bio: "A guy",
      name: "my name",
      nickname: "nick",
      password: "test",
      password_confirmation: "test",
      email: "email@example.com"
    }

vaartis's avatar
vaartis committed
113
    test "it requires an email, name, nickname and password, bio is optional" do
lain's avatar
lain committed
114
      @full_user_data
lain's avatar
lain committed
115 116
      |> Map.keys()
      |> Enum.each(fn key ->
lain's avatar
lain committed
117 118
        params = Map.delete(@full_user_data, key)
        changeset = User.register_changeset(%User{}, params)
vaartis's avatar
vaartis committed
119

lain's avatar
lain committed
120
        assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
lain's avatar
lain committed
121 122 123 124 125 126 127 128 129 130
      end)
    end

    test "it sets the password_hash, ap_id and following fields" do
      changeset = User.register_changeset(%User{}, @full_user_data)

      assert changeset.valid?

      assert is_binary(changeset.changes[:password_hash])
      assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
lain's avatar
lain committed
131 132 133 134 135

      assert changeset.changes[:following] == [
               User.ap_followers(%User{nickname: @full_user_data.nickname})
             ]

136
      assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
lain's avatar
lain committed
137 138
    end
  end
lain's avatar
lain committed
139 140 141 142 143 144 145 146 147

  describe "fetching a user from nickname or trying to build one" do
    test "gets an existing user" do
      user = insert(:user)
      fetched_user = User.get_or_fetch_by_nickname(user.nickname)

      assert user == fetched_user
    end

148 149 150 151 152 153 154
    test "gets an existing user, case insensitive" do
      user = insert(:user, nickname: "nick")
      fetched_user = User.get_or_fetch_by_nickname("NICK")

      assert user == fetched_user
    end

lain's avatar
lain committed
155 156 157 158 159 160 161 162 163
    test "fetches an external user via ostatus if no user exists" do
      fetched_user = User.get_or_fetch_by_nickname("shp@social.heldscal.la")
      assert fetched_user.nickname == "shp@social.heldscal.la"
    end

    test "returns nil if no user could be fetched" do
      fetched_user = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
      assert fetched_user == nil
    end
lain's avatar
lain committed
164 165 166 167 168

    test "returns nil for nonexistant local user" do
      fetched_user = User.get_or_fetch_by_nickname("nonexistant")
      assert fetched_user == nil
    end
lain's avatar
lain committed
169
  end
170 171 172

  test "returns an ap_id for a user" do
    user = insert(:user)
lain's avatar
lain committed
173 174 175 176 177 178 179

    assert User.ap_id(user) ==
             Pleroma.Web.Router.Helpers.o_status_url(
               Pleroma.Web.Endpoint,
               :feed_redirect,
               user.nickname
             )
180 181 182 183
  end

  test "returns an ap_followers link for a user" do
    user = insert(:user)
lain's avatar
lain committed
184 185 186 187 188 189 190

    assert User.ap_followers(user) ==
             Pleroma.Web.Router.Helpers.o_status_url(
               Pleroma.Web.Endpoint,
               :feed_redirect,
               user.nickname
             ) <> "/followers"
191
  end
lain's avatar
lain committed
192 193 194 195 196 197 198

  describe "remote user creation changeset" do
    @valid_remote %{
      bio: "hello",
      name: "Someone",
      nickname: "a@b.de",
      ap_id: "http...",
lain's avatar
lain committed
199 200
      info: %{some: "info"},
      avatar: %{some: "avatar"}
lain's avatar
lain committed
201 202 203 204 205 206 207
    }

    test "it confirms validity" do
      cs = User.remote_user_creation(@valid_remote)
      assert cs.valid?
    end

208 209 210
    test "it sets the follower_adress" do
      cs = User.remote_user_creation(@valid_remote)
      # remote users get a fake local follower address
lain's avatar
lain committed
211 212
      assert cs.changes.follower_address ==
               User.ap_followers(%User{nickname: @valid_remote[:nickname]})
213 214
    end

lain's avatar
lain committed
215 216
    test "it enforces the fqn format for nicknames" do
      cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
lain's avatar
lain committed
217 218
      assert cs.changes.local == false
      assert cs.changes.avatar
lain's avatar
lain committed
219 220 221 222
      refute cs.valid?
    end

    test "it has required fields" do
lain's avatar
lain committed
223
      [:name, :nickname, :ap_id]
lain's avatar
lain committed
224
      |> Enum.each(fn field ->
lain's avatar
lain committed
225 226 227 228 229 230
        cs = User.remote_user_creation(Map.delete(@valid_remote, field))
        refute cs.valid?
      end)
    end

    test "it restricts some sizes" do
lain's avatar
lain committed
231
      [bio: 5000, name: 100]
lain's avatar
lain committed
232
      |> Enum.each(fn {field, size} ->
lain's avatar
lain committed
233 234 235 236 237 238 239 240 241 242
        string = String.pad_leading(".", size)
        cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
        assert cs.valid?

        string = String.pad_leading(".", size + 1)
        cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
        refute cs.valid?
      end)
    end
  end
lain's avatar
lain committed
243 244 245 246 247 248 249 250 251 252 253 254 255

  describe "followers and friends" do
    test "gets all followers for a given user" do
      user = insert(:user)
      follower_one = insert(:user)
      follower_two = insert(:user)
      not_follower = insert(:user)

      {:ok, follower_one} = User.follow(follower_one, user)
      {:ok, follower_two} = User.follow(follower_two, user)

      {:ok, res} = User.get_followers(user)

lain's avatar
lain committed
256 257 258
      assert Enum.member?(res, follower_one)
      assert Enum.member?(res, follower_two)
      refute Enum.member?(res, not_follower)
lain's avatar
lain committed
259 260 261 262 263 264 265 266 267 268 269 270 271
    end

    test "gets all friends (followed users) for a given user" do
      user = insert(:user)
      followed_one = insert(:user)
      followed_two = insert(:user)
      not_followed = insert(:user)

      {:ok, user} = User.follow(user, followed_one)
      {:ok, user} = User.follow(user, followed_two)

      {:ok, res} = User.get_friends(user)

272 273
      followed_one = User.get_by_ap_id(followed_one.ap_id)
      followed_two = User.get_by_ap_id(followed_two.ap_id)
lain's avatar
lain committed
274 275 276
      assert Enum.member?(res, followed_one)
      assert Enum.member?(res, followed_two)
      refute Enum.member?(res, not_followed)
lain's avatar
lain committed
277 278
    end
  end
279 280 281 282 283 284 285 286 287 288 289 290 291 292

  describe "updating note and follower count" do
    test "it sets the info->note_count property" do
      note = insert(:note)

      user = User.get_by_ap_id(note.data["actor"])

      assert user.info["note_count"] == nil

      {:ok, user} = User.update_note_count(user)

      assert user.info["note_count"] == 1
    end

293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
    test "it increases the info->note_count property" do
      note = insert(:note)
      user = User.get_by_ap_id(note.data["actor"])

      assert user.info["note_count"] == nil

      {:ok, user} = User.increase_note_count(user)

      assert user.info["note_count"] == 1

      {:ok, user} = User.increase_note_count(user)

      assert user.info["note_count"] == 2
    end

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    test "it decreases the info->note_count property" do
      note = insert(:note)
      user = User.get_by_ap_id(note.data["actor"])

      assert user.info["note_count"] == nil

      {:ok, user} = User.increase_note_count(user)

      assert user.info["note_count"] == 1

      {:ok, user} = User.decrease_note_count(user)

      assert user.info["note_count"] == 0

      {:ok, user} = User.decrease_note_count(user)

      assert user.info["note_count"] == 0
    end

327 328 329 330 331 332 333 334 335 336 337 338 339
    test "it sets the info->follower_count property" do
      user = insert(:user)
      follower = insert(:user)

      User.follow(follower, user)

      assert user.info["follower_count"] == nil

      {:ok, user} = User.update_follower_count(user)

      assert user.info["follower_count"] == 1
    end
  end
lain's avatar
lain committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362

  describe "blocks" do
    test "it blocks people" do
      user = insert(:user)
      blocked_user = insert(:user)

      refute User.blocks?(user, blocked_user)

      {:ok, user} = User.block(user, blocked_user)

      assert User.blocks?(user, blocked_user)
    end

    test "it unblocks users" do
      user = insert(:user)
      blocked_user = insert(:user)

      {:ok, user} = User.block(user, blocked_user)
      {:ok, user} = User.unblock(user, blocked_user)

      refute User.blocks?(user, blocked_user)
    end
  end
363

eal's avatar
eal committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
  describe "domain blocking" do
    test "blocks domains" do
      user = insert(:user)
      collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})

      {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")

      assert User.blocks?(user, collateral_user)
    end

    test "unblocks domains" do
      user = insert(:user)
      collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})

      {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
      {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")

      refute User.blocks?(user, collateral_user)
    end
  end

385 386 387 388 389 390
  test "get recipients from activity" do
    actor = insert(:user)
    user = insert(:user, local: true)
    user_two = insert(:user, local: false)
    addressed = insert(:user, local: true)
    addressed_remote = insert(:user, local: false)
lain's avatar
lain committed
391 392 393 394 395

    {:ok, activity} =
      CommonAPI.post(actor, %{
        "status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
      })
396 397 398 399

    assert [addressed] == User.get_recipients_from_activity(activity)

    {:ok, user} = User.follow(user, actor)
lain's avatar
lain committed
400
    {:ok, _user_two} = User.follow(user_two, actor)
401 402 403 404 405
    recipients = User.get_recipients_from_activity(activity)
    assert length(recipients) == 2
    assert user in recipients
    assert addressed in recipients
  end
lain's avatar
lain committed
406

lain's avatar
lain committed
407 408 409 410 411 412
  test ".deactivate deactivates a user" do
    user = insert(:user)
    assert false == !!user.info["deactivated"]
    {:ok, user} = User.deactivate(user)
    assert true == user.info["deactivated"]
  end
lain's avatar
lain committed
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

  test ".delete deactivates a user, all follow relationships and all create activities" do
    user = insert(:user)
    followed = insert(:user)
    follower = insert(:user)

    {:ok, user} = User.follow(user, followed)
    {:ok, follower} = User.follow(follower, user)

    {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
    {:ok, activity_two} = CommonAPI.post(follower, %{"status" => "3hu"})

    {:ok, _, _} = CommonAPI.favorite(activity_two.id, user)
    {:ok, _, _} = CommonAPI.favorite(activity.id, follower)
    {:ok, _, _} = CommonAPI.repeat(activity.id, follower)

    :ok = User.delete(user)

    followed = Repo.get(User, followed.id)
    follower = Repo.get(User, follower.id)
    user = Repo.get(User, user.id)

    assert user.info["deactivated"]

    refute User.following?(user, followed)
    refute User.following?(followed, follower)

lain's avatar
lain committed
440 441 442
    # TODO: Remove favorites, repeats, delete activities.

    refute Repo.get(Activity, activity.id)
lain's avatar
lain committed
443
  end
444 445 446 447

  test "get_public_key_for_ap_id fetches a user that's not in the db" do
    assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
  end
lain's avatar
lain committed
448 449 450

  test "insert or update a user from given data" do
    user = insert(:user, %{nickname: "nick@name.de"})
lain's avatar
lain committed
451
    data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
lain's avatar
lain committed
452 453 454

    assert {:ok, %User{}} = User.insert_or_update_user(data)
  end
lain's avatar
lain committed
455
end