Merge branch 'develop' into feature/compat/push-subscriptions
[akkoma] / lib / pleroma / user.ex
index b3d0712d417cbc2ae66bedb0a54326d661cb3ea6..74ae5ef0d7e30c9905fc32e1ddb21fc78e7d9aeb 100644 (file)
@@ -4,6 +4,8 @@ defmodule Pleroma.User do
   import Ecto.{Changeset, Query}
   alias Pleroma.{Repo, User, Object, Web, Activity, Notification}
   alias Comeonin.Pbkdf2
+  alias Pleroma.Formatter
+  alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
   alias Pleroma.Web.{OStatus, Websub, OAuth}
   alias Pleroma.Web.ActivityPub.{Utils, ActivityPub}
 
@@ -36,13 +38,13 @@ defmodule Pleroma.User do
   end
 
   def banner_url(user) do
-    case user.info["banner"] do
+    case user.info.banner do
       %{"url" => [%{"href" => href} | _]} -> href
       _ -> "#{Web.base_url()}/images/banner.png"
     end
   end
 
-  def profile_url(%User{info: %{"source_data" => %{"url" => url}}}), do: url
+  def profile_url(%User{info: %{source_data: %{"url" => url}}}), do: url
   def profile_url(%User{ap_id: ap_id}), do: ap_id
   def profile_url(_), do: nil
 
@@ -61,9 +63,7 @@ defmodule Pleroma.User do
   end
 
   def info_changeset(struct, params \\ %{}) do
-    struct
-    |> cast(params, [:info])
-    |> validate_required([:info])
+    raise "NOT VALID ANYMORE"
   end
 
   def user_info(%User{} = user) do
@@ -80,18 +80,25 @@ defmodule Pleroma.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
+    params =
+      params
+      |> Map.put(:info, params[:info] || %{})
+
+    info_cng = User.Info.remote_user_creation(%User.Info{}, params[:info])
+
     changes =
       %User{}
-      |> cast(params, [:bio, :name, :ap_id, :nickname, :info, :avatar])
+      |> cast(params, [:bio, :name, :ap_id, :nickname, :avatar])
       |> validate_required([:name, :ap_id])
       |> unique_constraint(:nickname)
       |> validate_format(:nickname, @email_regex)
       |> validate_length(:bio, max: 5000)
       |> validate_length(:name, max: 100)
       |> put_change(:local, false)
+      |> put_embed(:info, info_cng)
 
     if changes.valid? do
-      case changes.changes[:info]["source_data"] do
+      case info_cng.changes[:source_data] do
         %{"followers" => followers} ->
           changes
           |> put_change(:follower_address, followers)
@@ -109,7 +116,7 @@ defmodule Pleroma.User do
 
   def update_changeset(struct, params \\ %{}) do
     struct
-    |> cast(params, [:bio, :name])
+    |> cast(params, [:bio, :name, :avatar])
     |> unique_constraint(:nickname)
     |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/)
     |> validate_length(:bio, max: 5000)
@@ -121,12 +128,17 @@ defmodule Pleroma.User do
       params
       |> Map.put(:last_refreshed_at, NaiveDateTime.utc_now())
 
+    info_cng =
+      struct.info
+      |> User.Info.user_upgrade(params[:info])
+
     struct
-    |> cast(params, [:bio, :name, :info, :follower_address, :avatar, :last_refreshed_at])
+    |> cast(params, [:bio, :name, :follower_address, :avatar, :last_refreshed_at])
     |> unique_constraint(:nickname)
     |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/)
     |> validate_length(:bio, max: 5000)
     |> validate_length(:name, max: 100)
+    |> put_embed(:info, info_cng)
   end
 
   def password_update_changeset(struct, params) do
@@ -165,6 +177,7 @@ defmodule Pleroma.User do
       |> validate_format(:email, @email_regex)
       |> validate_length(:bio, max: 1000)
       |> validate_length(:name, min: 1, max: 100)
+      |> put_change(:info, %Pleroma.User.Info{})
 
     if changeset.valid? do
       hashed = Pbkdf2.hashpwsalt(changeset.changes[:password])
@@ -191,7 +204,7 @@ defmodule Pleroma.User do
 
   def needs_update?(_), do: true
 
-  def maybe_direct_follow(%User{} = follower, %User{local: true, info: %{"locked" => true}}) do
+  def maybe_direct_follow(%User{} = follower, %User{local: true, info: %{locked: true}}) do
     {:ok, follower}
   end
 
@@ -274,7 +287,7 @@ defmodule Pleroma.User do
   end
 
   def locked?(%User{} = user) do
-    user.info["locked"] || false
+    user.info.locked || false
   end
 
   def get_by_ap_id(ap_id) do
@@ -592,21 +605,27 @@ defmodule Pleroma.User do
   end
 
   def block_domain(user, domain) do
-    domain_blocks = user.info.domain_blocks
-    new_blocks = Enum.uniq([domain | domain_blocks])
-    new_info = Map.put(user.info, "domain_blocks", new_blocks)
+    info_cng =
+      user.info
+      |> User.Info.add_to_domain_block(domain)
+
+    cng =
+      change(user)
+      |> put_embed(:info, info_cng)
 
-    cs = User.info_changeset(user, %{info: new_info})
-    update_and_set_cache(cs)
+    update_and_set_cache(cng)
   end
 
   def unblock_domain(user, domain) do
-    blocks = user.info["domain_blocks"] || []
-    new_blocks = List.delete(blocks, domain)
-    new_info = Map.put(user.info, "domain_blocks", new_blocks)
+    info_cng =
+      user.info
+      |> User.Info.remove_from_domain_block(domain)
+
+    cng =
+      change(user)
+      |> put_embed(:info, info_cng)
 
-    cs = User.info_changeset(user, %{info: new_info})
-    update_and_set_cache(cs)
+    update_and_set_cache(cng)
   end
 
   def local_user_query() do
@@ -666,7 +685,7 @@ defmodule Pleroma.User do
     {:ok, user}
   end
 
-  def html_filter_policy(%User{info: %{"no_rich_text" => true}}) do
+  def html_filter_policy(%User{info: %{no_rich_text: true}}) do
     Pleroma.HTML.Scrubber.TwitterText
   end
 
@@ -700,7 +719,7 @@ defmodule Pleroma.User do
       user
     else
       changes =
-        %User{}
+        %User{info: %User.Info{}}
         |> cast(%{}, [:ap_id, :nickname, :local])
         |> put_change(:ap_id, relay_uri)
         |> put_change(:nickname, nil)
@@ -714,7 +733,7 @@ defmodule Pleroma.User do
 
   # AP style
   def public_key_from_info(%{
-        "source_data" => %{"publicKey" => %{"publicKeyPem" => public_key_pem}}
+        source_data: %{"publicKey" => %{"publicKeyPem" => public_key_pem}}
       }) do
     key =
       :public_key.pem_decode(public_key_pem)
@@ -725,7 +744,7 @@ defmodule Pleroma.User do
   end
 
   # OStatus Magic Key
-  def public_key_from_info(%{"magic_key" => magic_key}) do
+  def public_key_from_info(%{magic_key: magic_key}) do
     {:ok, Pleroma.Web.Salmon.decode_key(magic_key)}
   end
 
@@ -747,11 +766,12 @@ defmodule Pleroma.User do
       |> Map.put(:name, blank?(data[:name]) || data[:nickname])
 
     cs = User.remote_user_creation(data)
+
     Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname)
   end
 
   def ap_enabled?(%User{local: true}), do: true
-  def ap_enabled?(%User{info: info}), do: info["ap_enabled"]
+  def ap_enabled?(%User{info: info}), do: info.ap_enabled
   def ap_enabled?(_), do: false
 
   def get_or_fetch(uri_or_nickname) do
@@ -785,4 +805,18 @@ defmodule Pleroma.User do
         :error
     end
   end
+
+  def parse_bio(bio, user \\ %User{info: %{source_data: %{}}}) do
+    mentions = Formatter.parse_mentions(bio)
+    tags = Formatter.parse_tags(bio)
+
+    emoji =
+      (user.info.source_data["tag"] || [])
+      |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
+      |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
+        {String.trim(name, ":"), url}
+      end)
+
+    CommonUtils.format_input(bio, mentions, tags, "text/plain") |> Formatter.emojify(emoji)
+  end
 end