accounts_test.exs 10.4 KB
Newer Older
1 2 3 4 5
# MoodleNet: Connecting and empowering educators worldwide
# Copyright © 2018-2019 Moodle Pty Ltd <https://moodle.com/moodlenet/>
# Contains code from Pleroma <https://pleroma.social/> and CommonsPub <https://commonspub.org/>
# SPDX-License-Identifier: AGPL-3.0-only

6 7 8 9
defmodule MoodleNet.AccountsTest do
  use MoodleNet.DataCase, async: true

  alias MoodleNet.Accounts
10
  alias MoodleNet.Accounts.{User, ResetPasswordToken}
11 12 13

  describe "register_user" do
    test "works" do
Alex Castaño's avatar
Alex Castaño committed
14
      icon_attrs = Factory.attributes(:image)
15
      image_attrs = Factory.attributes(:image)
16 17 18 19

      attrs =
        Factory.attributes(:user)
        |> Map.put("icon", icon_attrs)
20
        |> Map.put("image", image_attrs)
21 22
        |> Map.put("extra_field", "extra")

23
      Accounts.add_email_to_whitelist(attrs["email"])
Alex Castaño's avatar
Alex Castaño committed
24 25
      assert {:ok, ret} = Accounts.register_user(attrs)
      assert attrs["email"] == ret.user.email
26
      assert ret.actor
27 28
      assert attrs["preferred_username"] == ret.actor.preferred_username
      assert ret.actor["extra_field"] == attrs["extra_field"]
Alex Castaño's avatar
Alex Castaño committed
29
      assert [icon] = ret.actor[:icon]
30
      assert [icon_attrs["url"]] == get_in(ret, [:actor, :icon, Access.at(0), :url])
31
      assert [%{type: ["Object", "Place"]}] = ret.actor.location
32 33
      assert [image] = ret.actor[:image]
      assert [image_attrs["url"]] == get_in(ret, [:actor, :image, Access.at(0), :url])
34 35

      assert_delivered_email(MoodleNet.Email.welcome(ret.user, ret.email_confirmation_token.token))
36 37
    end

Alex Castaño's avatar
Alex Castaño committed
38 39 40 41 42 43
    test "works with moodle.com emails" do
      attrs = Factory.attributes(:user, email: "any_email_or_whatever@moodle.com")

      assert {:ok, _} = Accounts.register_user(attrs)
    end

Alex Castaño's avatar
Alex Castaño committed
44 45 46 47 48 49 50 51
    test "set gravatar icon by default" do
      attrs = Factory.attributes(:user, email: "alex@moodle.com")
              |> Map.delete("icon")

      assert {:ok, %{actor: actor}} = Accounts.register_user(attrs)
      assert ["https://s.gravatar.com/avatar/7779b850ea05dbeca7fc39a910a77f21?d=identicon&r=g&s=80"] == get_in(actor, [:icon, Access.at(0), :url])
    end

52 53 54 55 56 57 58
    test "set default header image" do
      attrs = Factory.attributes(:user, email: "karenk@moodle.com")
              |> Map.delete("image")
              
      assert {:ok, %{actor: actor}} = Accounts.register_user(attrs)
      assert ["https://images.unsplash.com/photo-1557943978-bea7e84f0e87?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60"] == get_in(actor, [:image, Access.at(0), :url])
    end
Alex Castaño's avatar
Alex Castaño committed
59

60
    test "fails with invalid password values" do
61
      attrs = Factory.attributes(:user) |> Map.delete("password")
62
      Accounts.add_email_to_whitelist(attrs["email"])
63 64 65
      assert {:error, _, ch, _} = Accounts.register_user(attrs)
      assert "can't be blank" in errors_on(ch).password

66
      attrs = Factory.attributes(:user) |> Map.put("password", "short")
67
      Accounts.add_email_to_whitelist(attrs["email"])
68 69 70 71 72
      assert {:error, _, ch, _} = Accounts.register_user(attrs)
      assert "should be at least 6 character(s)" in errors_on(ch).password
    end

    test "fails with invalid email" do
73
      attrs = Factory.attributes(:user) |> Map.delete("email")
74 75 76
      assert {:error, _, ch, _} = Accounts.register_user(attrs)
      assert "can't be blank" in errors_on(ch).email

77
      attrs = Factory.attributes(:user) |> Map.put("email", "not_an_email")
78
      Accounts.add_email_to_whitelist(attrs["email"])
79 80 81 82 83
      assert {:error, _, ch, _} = Accounts.register_user(attrs)
      assert "has invalid format" in errors_on(ch).email
    end

    test "lower case the email" do
84 85 86
      attrs = Factory.attributes(:user)
      email = attrs["email"]
      attrs = Map.put(attrs, "email", String.upcase(attrs["email"]))
87
      Accounts.add_email_to_whitelist(attrs["email"])
88
      assert {:ok, ret} = Accounts.register_user(attrs)
89
      assert ret.user.email == email
90 91 92
    end
  end

Alex Castaño's avatar
Alex Castaño committed
93 94
  describe "update_user/2" do
    test "works" do
95
      actor = Factory.actor(location: nil, attachment: nil, image: nil)
Alex Castaño's avatar
Alex Castaño committed
96 97 98 99 100 101
      attrs = %{
        name: "name",
        preferred_username: "username",
        locale: "fr",
        primary_language: "cz",
        summary: "summary",
102
        image: "https://images.unsplash.com/flagged/photo-1551255868-86bbc8e0f971",
103 104
        location: nil,
        website: nil
Alex Castaño's avatar
Alex Castaño committed
105 106
      }
      assert {:ok, actor} = MoodleNet.Accounts.update_user(actor, attrs)
107
      assert [%{url: ["https://images.unsplash.com/flagged/photo-1551255868-86bbc8e0f971"]}] = actor.image
Alex Castaño's avatar
Alex Castaño committed
108 109 110 111 112 113 114
      assert actor.name == %{"und" => attrs.name}
      assert actor.summary == %{"und" => attrs.summary}
      assert actor.preferred_username == attrs.preferred_username
      assert actor["locale"] == "fr"
      assert actor["primary_language"] == "cz"
      assert actor.location == []

115 116 117
      assert {:ok, actor} = MoodleNet.Accounts.update_user(actor, %{image: "https://images.unsplash.com/photo-1557943978-bea7e84f0e87"})
      assert [%{url: ["https://images.unsplash.com/photo-1557943978-bea7e84f0e87"]}] = actor.image

Alex Castaño's avatar
Alex Castaño committed
118
      assert {:ok, actor} = MoodleNet.Accounts.update_user(actor, %{location: "location"})
119
      assert [%{content: %{"und" => "location"}, type: ["Object", "Place"]}] = actor.location
Alex Castaño's avatar
Alex Castaño committed
120 121 122

      assert {:ok, actor} = MoodleNet.Accounts.update_user(actor, %{location: nil})
      assert [] == actor.location
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

      assert {:ok, actor} = MoodleNet.Accounts.update_user(actor, %{website: "kawen.space"})
      assert [%{
        :name => %{"und" => "Website"},
        :type => ["Object", "PropertyValue"],
        "value" => "kawen.space"
      }] = actor.attachment

      assert {:ok, actor} = MoodleNet.Accounts.update_user(actor, %{website: "testing.kawen.dance"})
      assert [%{
        :name => %{"und" => "Website"},
        :type => ["Object", "PropertyValue"],
        "value" => "testing.kawen.dance"
      }] = actor.attachment

      assert {:ok, actor} = MoodleNet.Accounts.update_user(actor, %{website: nil})
      assert [] == actor.attachment
Alex Castaño's avatar
Alex Castaño committed
140 141 142
    end
  end

143 144
  describe "authenticate_by_email_and_pass" do
    test "works" do
145
      user = %{id: user_id} = Factory.user()
146

147
      assert {:ok, %User{id: ^user_id}} =
148
               Accounts.authenticate_by_email_and_pass(user.email, "password")
149 150

      assert {:error, :unauthorized} =
151
               Accounts.authenticate_by_email_and_pass(user.email, "other_thing")
152 153

      assert {:error, :not_found} =
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
               Accounts.authenticate_by_email_and_pass("other@email.es", "password")
    end
  end

  describe "reset_password_request" do
    test "works" do
      user = Factory.user()
      assert {:ok, %{token: token}} = Accounts.reset_password_request(user.email)

      assert %{token: ^token} = Repo.get_by!(ResetPasswordToken, user_id: user.id)

      assert_delivered_email(MoodleNet.Email.reset_password_request(user, token))

      assert {:ok, %{token: new_token}} = Accounts.reset_password_request(user.email)
      assert %{token: ^new_token} = Repo.get_by!(ResetPasswordToken, user_id: user.id)
      assert token != new_token
    end

    test "returns error if email not found" do
173
      assert {:error, {:not_found, "not_found", "User"}} = Accounts.reset_password_request("not_found")
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    end
  end

  describe "reset_password" do
    test " works" do
      user = Factory.user()
      assert {:ok, %{token: token}} = Accounts.reset_password_request(user.email)
      assert {:ok, _} = Accounts.reset_password(token, "new_password")

      refute Repo.get_by(ResetPasswordToken, user_id: user.id)
      assert {:ok, _} = Accounts.authenticate_by_email_and_pass(user.email, "new_password")

      assert_delivered_email(MoodleNet.Email.password_reset(user))
    end

    test "returns error with invalid password" do
      user = Factory.user()
      assert {:ok, %{token: token}} = Accounts.reset_password_request(user.email)
      assert {:error, :password_hash, ch, _} = Accounts.reset_password(token, "short")
      assert "should be at least 6 character(s)" in errors_on(ch)[:password]
    end

    @three_days 60 * 60 * 24 * 3
    test "returns error with expired tokens" do
      user = Factory.user()

      token = MoodleNet.Token.random_key_with_id(user.id)
      date =
        NaiveDateTime.utc_now()
        |> NaiveDateTime.truncate(:second)
        |> NaiveDateTime.add(-@three_days)
      token = Repo.insert!(%ResetPasswordToken{token: token, user_id: user.id, inserted_at: date})

207
      assert {:error, {:not_found, _, "Token"}} = Accounts.reset_password(token.token, "new_password")
208 209 210
    end

    test "returns error if token not found" do
211
      assert {:error, {:not_found, _, "Token"}} = Accounts.reset_password("1234", "new_password")
212 213 214

      user = Factory.user()
      token = MoodleNet.Token.random_key_with_id(user.id)
215
      assert {:error, {:not_found, _, "Token"}} = Accounts.reset_password(token, "new_password")
216 217

      assert {:ok, %{token: token}} = Accounts.reset_password_request(user.email)
218
      assert {:error, {:not_found, _, "Token"}} = Accounts.reset_password(token <> "1", "new_password")
219 220 221 222 223 224 225 226 227 228 229 230 231
    end
  end

  describe "confirm_email" do
    test "works" do
      %{user: user, email_confirmation_token: %{token: token}} = Factory.full_user()
      assert {:ok, _} = Accounts.confirm_email(token)
      refute user.confirmed_at
      assert Repo.get(User, user.id).confirmed_at
      refute Repo.get_by(Accounts.EmailConfirmationToken, user_id: user.id)
    end

    test "returns error if token not found" do
232
      assert {:error, {:not_found, "1234", "Token"}} = Accounts.confirm_email("1234")
233 234

      %{user: user, email_confirmation_token: %{token: token}} = Factory.full_user()
235 236
      assert {:error, {:not_found, _, "Token"}} = Accounts.confirm_email(MoodleNet.Token.random_key_with_id(user.id))
      assert {:error, {:not_found, _, "Token"}} = Accounts.confirm_email(token <> "1")
237 238
    end
  end
239 240 241 242 243 244 245 246 247 248 249 250

  describe "whitelist" do
    test "works" do
      email = Faker.Internet.safe_email()
      refute Accounts.is_email_in_whitelist?(email)
      assert {:ok, _} = Accounts.add_email_to_whitelist(email)
      assert Accounts.is_email_in_whitelist?(email)
      assert {:ok, _} = Accounts.remove_email_from_whitelist(email)
      refute Accounts.is_email_in_whitelist?(email)
      assert {:error, _} = Accounts.remove_email_from_whitelist(email)
    end
  end
251 252 253 254 255 256 257 258 259 260 261 262 263 264

  describe "delete_user" do
    test "set to empty the comments" do
      actor = Factory.actor()
      community = Factory.community(actor)
      comment = Factory.comment(actor, community)

      Accounts.delete_user(actor)

      reload_comment = ActivityPub.SQL.Query.get_by_id(comment.id)

      assert reload_comment.content == %{"und" => ""}
    end
  end
265
end