diff options
| author | rinpatch <rinpatch@sdf.org> | 2018-12-03 00:34:04 +0300 | 
|---|---|---|
| committer | rinpatch <rinpatch@sdf.org> | 2018-12-03 00:34:04 +0300 | 
| commit | 343b0adfa6c88f0934d788be0e59ea8a5fe483b1 (patch) | |
| tree | a6debba90a247854543aad4069f1b2e3d9ebd1b1 /lib | |
| parent | a3953ca37ab4122772119ae345705e712e23dd17 (diff) | |
| parent | 371d96b1da85960dafea9665b8bc32ba553b1555 (diff) | |
| download | pleroma-343b0adfa6c88f0934d788be0e59ea8a5fe483b1.tar.gz pleroma-343b0adfa6c88f0934d788be0e59ea8a5fe483b1.zip  | |
Merge branch 'develop' into fix/theora-detection-read-bytes
Diffstat (limited to 'lib')
23 files changed, 424 insertions, 267 deletions
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 26bb17377..1a5c07c8a 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -116,8 +116,8 @@ defmodule Pleroma.Formatter do        subs ++          Enum.map(mentions, fn {match, %User{ap_id: ap_id, info: info}, uuid} ->            ap_id = -            if is_binary(info["source_data"]["url"]) do -              info["source_data"]["url"] +            if is_binary(info.source_data["url"]) do +              info.source_data["url"]              else                ap_id              end diff --git a/lib/pleroma/plugs/oauth_plug.ex b/lib/pleroma/plugs/oauth_plug.ex index 0380ce14d..630f15eec 100644 --- a/lib/pleroma/plugs/oauth_plug.ex +++ b/lib/pleroma/plugs/oauth_plug.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Plugs.OAuthPlug do      with token when not is_nil(token) <- token,           %Token{user_id: user_id} <- Repo.get_by(Token, token: token),           %User{} = user <- Repo.get(User, user_id), -         false <- !!user.info["deactivated"] do +         false <- !!user.info.deactivated do        conn        |> assign(:user, user)      else diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex index 9c3285896..01482f47d 100644 --- a/lib/pleroma/plugs/user_enabled_plug.ex +++ b/lib/pleroma/plugs/user_enabled_plug.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Plugs.UserEnabledPlug do      options    end -  def call(%{assigns: %{user: %User{info: %{"deactivated" => true}}}} = conn, _) do +  def call(%{assigns: %{user: %User{info: %{deactivated: true}}}} = conn, _) do      conn      |> assign(:user, nil)    end diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index 5312f1499..cf22ce5d0 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do      options    end -  def call(%{assigns: %{user: %User{info: %{"is_admin" => true}}}} = conn, _) do +  def call(%{assigns: %{user: %User{info: %{is_admin: true}}}} = conn, _) do      conn    end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 6e1d5559d..76712b4bf 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -19,11 +19,11 @@ defmodule Pleroma.User do      field(:ap_id, :string)      field(:avatar, :map)      field(:local, :boolean, default: true) -    field(:info, :map, default: %{})      field(:follower_address, :string)      field(:search_distance, :float, virtual: true)      field(:last_refreshed_at, :naive_datetime)      has_many(:notifications, Notification) +    embeds_one(:info, Pleroma.User.Info)      timestamps()    end @@ -36,13 +36,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 +61,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 @@ -71,27 +69,34 @@ defmodule Pleroma.User do      %{        following_count: length(user.following) - oneself, -      note_count: user.info["note_count"] || 0, -      follower_count: user.info["follower_count"] || 0, -      locked: user.info["locked"] || false, -      default_scope: user.info["default_scope"] || "public" +      note_count: user.info.note_count, +      follower_count: user.info.follower_count, +      locked: user.info.locked, +      default_scope: user.info.default_scope      }    end    @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 +114,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 +126,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 @@ -191,7 +201,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 @@ -222,7 +232,7 @@ defmodule Pleroma.User do      ap_followers = followed.follower_address      cond do -      following?(follower, followed) or info["deactivated"] -> +      following?(follower, followed) or info.deactivated ->          {:error, "Could not follow user: #{followed.nickname} is already on your list."}        deny_follow_blocked and blocks?(followed, follower) -> @@ -274,7 +284,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 @@ -411,22 +421,23 @@ defmodule Pleroma.User do    end    def increase_note_count(%User{} = user) do -    note_count = (user.info["note_count"] || 0) + 1 -    new_info = Map.put(user.info, "note_count", note_count) +    info_cng = User.Info.add_to_note_count(user.info, 1) -    cs = info_changeset(user, %{info: new_info}) +    cng = +      change(user) +      |> put_embed(:info, info_cng) -    update_and_set_cache(cs) +    update_and_set_cache(cng)    end    def decrease_note_count(%User{} = user) do -    note_count = user.info["note_count"] || 0 -    note_count = if note_count <= 0, do: 0, else: note_count - 1 -    new_info = Map.put(user.info, "note_count", note_count) +    info_cng = User.Info.add_to_note_count(user.info, -1) -    cs = info_changeset(user, %{info: new_info}) +    cng = +      change(user) +      |> put_embed(:info, info_cng) -    update_and_set_cache(cs) +    update_and_set_cache(cng)    end    def update_note_count(%User{} = user) do @@ -439,11 +450,13 @@ defmodule Pleroma.User do      note_count = Repo.one(note_count_query) -    new_info = Map.put(user.info, "note_count", note_count) +    info_cng = User.Info.set_note_count(user.info, note_count) -    cs = info_changeset(user, %{info: new_info}) +    cng = +      change(user) +      |> put_embed(:info, info_cng) -    update_and_set_cache(cs) +    update_and_set_cache(cng)    end    def update_follower_count(%User{} = user) do @@ -457,11 +470,15 @@ defmodule Pleroma.User do      follower_count = Repo.one(follower_count_query) -    new_info = Map.put(user.info, "follower_count", follower_count) +    info_cng = +      user.info +      |> User.Info.set_follower_count(follower_count) -    cs = info_changeset(user, %{info: new_info}) +    cng = +      change(user) +      |> put_embed(:info, info_cng) -    update_and_set_cache(cs) +    update_and_set_cache(cng)    end    def get_users_from_set_query(ap_ids, false) do @@ -545,12 +562,15 @@ defmodule Pleroma.User do        unfollow(blocked, blocker)      end -    blocks = blocker.info["blocks"] || [] -    new_blocks = Enum.uniq([ap_id | blocks]) -    new_info = Map.put(blocker.info, "blocks", new_blocks) +    info_cng = +      blocker.info +      |> User.Info.add_to_block(ap_id) + +    cng = +      change(blocker) +      |> put_embed(:info, info_cng) -    cs = User.info_changeset(blocker, %{info: new_info}) -    update_and_set_cache(cs) +    update_and_set_cache(cng)    end    # helper to handle the block given only an actor's AP id @@ -558,18 +578,21 @@ defmodule Pleroma.User do      block(blocker, User.get_by_ap_id(ap_id))    end -  def unblock(user, %{ap_id: ap_id}) do -    blocks = user.info["blocks"] || [] -    new_blocks = List.delete(blocks, ap_id) -    new_info = Map.put(user.info, "blocks", new_blocks) +  def unblock(blocker, %{ap_id: ap_id}) do +    info_cng = +      blocker.info +      |> User.Info.remove_from_block(ap_id) -    cs = User.info_changeset(user, %{info: new_info}) -    update_and_set_cache(cs) +    cng = +      change(blocker) +      |> put_embed(:info, info_cng) + +    update_and_set_cache(cng)    end    def blocks?(user, %{ap_id: ap_id}) do -    blocks = user.info["blocks"] || [] -    domain_blocks = user.info["domain_blocks"] || [] +    blocks = user.info.blocks +    domain_blocks = user.info.domain_blocks      %{host: host} = URI.parse(ap_id)      Enum.member?(blocks, ap_id) || @@ -579,21 +602,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 @@ -613,9 +642,13 @@ defmodule Pleroma.User do    end    def deactivate(%User{} = user, status \\ true) do -    new_info = Map.put(user.info, "deactivated", status) -    cs = User.info_changeset(user, %{info: new_info}) -    update_and_set_cache(cs) +    info_cng = User.Info.set_activation_status(user.info, status) + +    cng = +      change(user) +      |> put_embed(:info, info_cng) + +    update_and_set_cache(cng)    end    def delete(%User{} = user) do @@ -649,7 +682,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 @@ -683,7 +716,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) @@ -697,7 +730,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) @@ -708,7 +741,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 @@ -730,11 +763,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 diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex new file mode 100644 index 000000000..94d403bf7 --- /dev/null +++ b/lib/pleroma/user/info.ex @@ -0,0 +1,164 @@ +defmodule Pleroma.User.Info do +  use Ecto.Schema +  import Ecto.Changeset + +  embedded_schema do +    field(:banner, :map, default: %{}) +    field(:background, :string, default: nil) +    field(:source_data, :map, default: %{}) +    field(:note_count, :integer, default: 0) +    field(:follower_count, :integer, default: 0) +    field(:locked, :boolean, default: false) +    field(:default_scope, :string, default: "public") +    field(:blocks, {:array, :string}, default: []) +    field(:domain_blocks, {:array, :string}, default: []) +    field(:deactivated, :boolean, default: false) +    field(:no_rich_text, :boolean, default: false) +    field(:ap_enabled, :boolean, default: false) +    field(:is_moderator, :boolean, default: false) +    field(:is_admin, :boolean, default: false) +    field(:keys, :string, default: nil) +    field(:settings, :map, default: nil) +    field(:magic_key, :string, default: nil) +    field(:uri, :string, default: nil) +    field(:topic, :string, default: nil) +    field(:hub, :string, default: nil) +    field(:salmon, :string, default: nil) + +    # Found in the wild +    # ap_id -> Where is this used? +    # bio -> Where is this used? +    # avatar -> Where is this used? +    # fqn -> Where is this used? +    # host -> Where is this used? +    # subject _> Where is this used? +  end + +  def set_activation_status(info, deactivated) do +    params = %{deactivated: deactivated} + +    info +    |> cast(params, [:deactivated]) +    |> validate_required([:deactivated]) +  end + +  def add_to_note_count(info, number) do +    set_note_count(info, info.note_count + number) +  end + +  def set_note_count(info, number) do +    params = %{note_count: Enum.max([0, number])} + +    info +    |> cast(params, [:note_count]) +    |> validate_required([:note_count]) +  end + +  def set_follower_count(info, number) do +    params = %{follower_count: Enum.max([0, number])} + +    info +    |> cast(params, [:follower_count]) +    |> validate_required([:follower_count]) +  end + +  def set_blocks(info, blocks) do +    params = %{blocks: blocks} + +    info +    |> cast(params, [:blocks]) +    |> validate_required([:blocks]) +  end + +  def add_to_block(info, blocked) do +    set_blocks(info, Enum.uniq([blocked | info.blocks])) +  end + +  def remove_from_block(info, blocked) do +    set_blocks(info, List.delete(info.blocks, blocked)) +  end + +  def set_domain_blocks(info, domain_blocks) do +    params = %{domain_blocks: domain_blocks} + +    info +    |> cast(params, [:domain_blocks]) +    |> validate_required([:domain_blocks]) +  end + +  def add_to_domain_block(info, domain_blocked) do +    set_domain_blocks(info, Enum.uniq([domain_blocked | info.domain_blocks])) +  end + +  def remove_from_domain_block(info, domain_blocked) do +    set_domain_blocks(info, List.delete(info.domain_blocks, domain_blocked)) +  end + +  def set_keys(info, keys) do +    params = %{keys: keys} + +    info +    |> cast(params, [:keys]) +    |> validate_required([:keys]) +  end + +  def remote_user_creation(info, params) do +    info +    |> cast(params, [ +      :ap_enabled, +      :source_data, +      :banner, +      :locked, +      :magic_key, +      :uri, +      :hub, +      :topic, +      :salmon +    ]) +  end + +  def user_upgrade(info, params) do +    info +    |> cast(params, [ +      :ap_enabled, +      :source_data, +      :banner, +      :locked, +      :magic_key +    ]) +  end + +  def profile_update(info, params) do +    info +    |> cast(params, [ +      :locked, +      :no_rich_text, +      :default_scope, +      :banner +    ]) +  end + +  def mastodon_profile_update(info, params) do +    info +    |> cast(params, [ +      :locked, +      :banner +    ]) +  end + +  def set_source_data(info, source_data) do +    params = %{source_data: source_data} + +    info +    |> cast(params, [:source_data]) +    |> validate_required([:source_data]) +  end + +  def admin_api_update(info, params) do +    info +    |> cast(params, [ +      :is_moderator, +      :is_admin +    ]) +  end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 76c15cf21..7e207c620 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -42,7 +42,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp check_actor_is_active(actor) do      if not is_nil(actor) do        with user <- User.get_cached_by_ap_id(actor), -           false <- !!user.info["deactivated"] do +           false <- user.info.deactivated do          :ok        else          _e -> :reject @@ -509,8 +509,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    end    defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do -    blocks = info["blocks"] || [] -    domain_blocks = info["domain_blocks"] || [] +    blocks = info.blocks || [] +    domain_blocks = info.domain_blocks || []      from(        activity in query, @@ -676,7 +676,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      remote_inboxes =        (Pleroma.Web.Salmon.remote_users(activity) ++ followers)        |> Enum.filter(fn user -> User.ap_enabled?(user) end) -      |> Enum.map(fn %{info: %{"source_data" => data}} -> +      |> Enum.map(fn %{info: %{source_data: data}} ->          (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]        end)        |> Enum.uniq() diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 5864855b0..17b063609 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -447,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do        update_data =          new_user_data          |> Map.take([:name, :bio, :avatar]) -        |> Map.put(:info, Map.merge(actor.info, %{"banner" => banner, "locked" => locked})) +        |> Map.put(:info, %{"banner" => banner, "locked" => locked})        actor        |> User.upgrade_changeset(update_data) @@ -850,10 +850,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    def upgrade_user_from_ap_id(ap_id, async \\ true) do      with %User{local: false} = user <- User.get_by_ap_id(ap_id),           {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id) do -      data = -        data -        |> Map.put(:info, Map.merge(user.info, data[:info])) -        already_ap = User.ap_enabled?(user)        {:ok, user} = diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index eb335813d..aaa777602 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do    # the instance itself is not a Person, but instead an Application    def render("user.json", %{user: %{nickname: nil} = user}) do      {:ok, user} = WebFinger.ensure_keys_present(user) -    {:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"]) +    {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys)      public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)      public_key = :public_key.pem_encode([public_key]) @@ -40,7 +40,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do    def render("user.json", %{user: user}) do      {:ok, user} = WebFinger.ensure_keys_present(user) -    {:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"]) +    {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys)      public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)      public_key = :public_key.pem_encode([public_key]) @@ -55,7 +55,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do        "name" => user.name,        "summary" => user.bio,        "url" => user.ap_id, -      "manuallyApprovesFollowers" => user.info["locked"] || false, +      "manuallyApprovesFollowers" => user.info.locked,        "publicKey" => %{          "id" => "#{user.ap_id}#main-key",          "owner" => user.ap_id, @@ -72,7 +72,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do          "type" => "Image",          "url" => User.banner_url(user)        }, -      "tag" => user.info["source_data"]["tag"] || [] +      "tag" => user.info.source_data["tag"] || []      }      |> Map.merge(Utils.make_json_ld_header())    end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index bcdb4ba37..2c67d9cda 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -45,21 +45,29 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do      user = User.get_by_nickname(nickname)      info = -      user.info +      %{}        |> Map.put("is_" <> permission_group, true) -    cng = User.info_changeset(user, %{info: info}) +    info_cng = User.Info.admin_api_update(user.info, info) + +    cng = +      Ecto.Changeset.change(user) +      |> Ecto.Changeset.put_embed(:info, info_cng) +      {:ok, user} = User.update_and_set_cache(cng)      conn -    |> json(user.info) +    |> json(info)    end    def right_get(conn, %{"nickname" => nickname}) do      user = User.get_by_nickname(nickname)      conn -    |> json(user.info) +    |> json(%{ +      is_moderator: user.info.is_moderator, +      is_admin: user.info.is_admin +    })    end    def right_add(conn, _) do @@ -84,14 +92,19 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do        user = User.get_by_nickname(nickname)        info = -        user.info +        %{}          |> Map.put("is_" <> permission_group, false) -      cng = User.info_changeset(user, %{info: info}) +      info_cng = User.Info.admin_api_update(user.info, info) + +      cng = +        Ecto.Changeset.change(user) +        |> Ecto.Changeset.put_embed(:info, info_cng) +        {:ok, user} = User.update_and_set_cache(cng)        conn -      |> json(user.info) +      |> json(info)      end    end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 77e4dbbd7..e3385310f 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Web.CommonAPI do    def delete(activity_id, user) do      with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),           %Object{} = object <- Object.normalize(object_id), -         true <- user.info["is_moderator"] || user.ap_id == object.data["actor"], +         true <- user.info.is_moderator || user.ap_id == object.data["actor"],           {:ok, delete} <- ActivityPub.delete(object) do        {:ok, delete}      end @@ -135,12 +135,13 @@ defmodule Pleroma.Web.CommonAPI do      end    end +  # Updates the emojis for a user based on their profile    def update(user) do      user =        with emoji <- emoji_from_profile(user), -           source_data <- (user.info["source_data"] || %{}) |> Map.put("tag", emoji), -           new_info <- Map.put(user.info, "source_data", source_data), -           change <- User.info_changeset(user, %{info: new_info}), +           source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji), +           info_cng <- Pleroma.User.Info.set_source_data(user.info, source_data), +           change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),             {:ok, user} <- User.update_and_set_cache(change) do          user        else diff --git a/lib/pleroma/web/http_signatures/http_signatures.ex b/lib/pleroma/web/http_signatures/http_signatures.ex index 5e42a871b..0e54debd5 100644 --- a/lib/pleroma/web/http_signatures/http_signatures.ex +++ b/lib/pleroma/web/http_signatures/http_signatures.ex @@ -65,7 +65,7 @@ defmodule Pleroma.Web.HTTPSignatures do    end    def sign(user, headers) do -    with {:ok, %{info: %{"keys" => keys}}} <- Pleroma.Web.WebFinger.ensure_keys_present(user), +    with {:ok, %{info: %{keys: keys}}} <- Pleroma.Web.WebFinger.ensure_keys_present(user),           {:ok, private_key, _} = Pleroma.Web.Salmon.keys_from_pem(keys) do        sigstring = build_signing_string(headers, Map.keys(headers)) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 009be50e7..d19d55044 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -32,67 +32,55 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end -  def update_credentials(%{assigns: %{user: user}} = conn, params) do -    original_user = user - -    params = -      if bio = params["note"] do -        Map.put(params, "bio", bio) -      else -        params +  defp add_if_present( +         map, +         params, +         params_field, +         map_field, +         value_function \\ fn x -> {:ok, x} end +       ) do +    if Map.has_key?(params, params_field) do +      case value_function.(params[params_field]) do +        {:ok, new_value} -> Map.put(map, map_field, new_value) +        :error -> map        end +    else +      map +    end +  end -    params = -      if name = params["display_name"] do -        Map.put(params, "name", name) -      else -        params -      end +  def update_credentials(%{assigns: %{user: user}} = conn, params) do +    original_user = user -    user = -      if avatar = params["avatar"] do -        with %Plug.Upload{} <- avatar, -             {:ok, object} <- ActivityPub.upload(avatar, type: :avatar), -             change = Ecto.Changeset.change(user, %{avatar: object.data}), -             {:ok, user} = User.update_and_set_cache(change) do -          user +    user_params = +      %{} +      |> add_if_present(params, "display_name", :name) +      |> add_if_present(params, "note", :bio) +      |> add_if_present(params, "avatar", :avatar, fn value -> +        with %Plug.Upload{} <- value, +             {:ok, object} <- ActivityPub.upload(value, type: :avatar) do +          {:ok, object.data}          else -          _e -> user +          _ -> :error          end -      else -        user -      end +      end) -    user = -      if banner = params["header"] do -        with %Plug.Upload{} <- banner, -             {:ok, object} <- ActivityPub.upload(banner, type: :banner), -             new_info <- Map.put(user.info, "banner", object.data), -             change <- User.info_changeset(user, %{info: new_info}), -             {:ok, user} <- User.update_and_set_cache(change) do -          user +    info_params = +      %{} +      |> add_if_present(params, "locked", :locked, fn value -> {:ok, value == "true"} end) +      |> add_if_present(params, "header", :banner, fn value -> +        with %Plug.Upload{} <- value, +             {:ok, object} <- ActivityPub.upload(value, type: :banner) do +          {:ok, object.data}          else -          _e -> user +          _ -> :error          end -      else -        user -      end +      end) -    user = -      if locked = params["locked"] do -        with locked <- locked == "true", -             new_info <- Map.put(user.info, "locked", locked), -             change <- User.info_changeset(user, %{info: new_info}), -             {:ok, user} <- User.update_and_set_cache(change) do -          user -        else -          _e -> user -        end -      else -        user -      end +    info_cng = User.Info.mastodon_profile_update(user.info, info_params) -    with changeset <- User.update_changeset(user, params), +    with changeset <- User.update_changeset(user, user_params), +         changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),           {:ok, user} <- User.update_and_set_cache(changeset) do        if original_user != user do          CommonAPI.update(user) @@ -644,7 +632,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do    # TODO: Use proper query    def blocks(%{assigns: %{user: user}} = conn, _) do -    with blocked_users <- user.info["blocks"] || [], +    with blocked_users <- user.info.blocks || [],           accounts <- Enum.map(blocked_users, fn ap_id -> User.get_cached_by_ap_id(ap_id) end) do        res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)        json(conn, res) @@ -652,7 +640,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do    end    def domain_blocks(%{assigns: %{user: %{info: info}}} = conn, _) do -    json(conn, info["domain_blocks"] || []) +    json(conn, info.domain_blocks || [])    end    def block_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do @@ -900,11 +888,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do              max_toot_chars: limit            },            rights: %{ -            delete_others_notice: !!user.info["is_moderator"] +            delete_others_notice: !!user.info.is_moderator            },            compose: %{              me: "#{user.id}", -            default_privacy: user.info["default_scope"] || "public", +            default_privacy: user.info.default_scope,              default_sensitive: false            },            media_attachments: %{ @@ -924,7 +912,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do              ]            },            settings: -            Map.get(user.info, "settings") || +            Map.get(user.info, :settings) ||                %{                  onboarded: true,                  home: %{ diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b68845e16..bcfa8836e 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -14,10 +14,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do      image = User.avatar_url(user) |> MediaProxy.url()      header = User.banner_url(user) |> MediaProxy.url()      user_info = User.user_info(user) -    bot = (user.info["source_data"]["type"] || "Person") in ["Application", "Service"] +    bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"]      emojis = -      (user.info["source_data"]["tag"] || []) +      (user.info.source_data["tag"] || [])        |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)        |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->          %{ @@ -29,7 +29,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do        end)      fields = -      (user.info["source_data"]["attachment"] || []) +      (user.info.source_data["attachment"] || [])        |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)        |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 1d0019d3b..6a27f1730 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -226,25 +226,21 @@ defmodule Pleroma.Web.OStatus do      old_data = %{        avatar: user.avatar,        bio: user.bio, -      name: user.name, -      info: user.info +      name: user.name      }      with false <- user.local,           avatar <- make_avatar_object(doc),           bio <- string_from_xpath("//author[1]/summary", doc),           name <- string_from_xpath("//author[1]/poco:displayName", doc), -         info <- -           Map.put(user.info, "banner", make_avatar_object(doc, "header") || user.info["banner"]),           new_data <- %{             avatar: avatar || old_data.avatar,             name: name || old_data.name, -           bio: bio || old_data.bio, -           info: info || old_data.info +           bio: bio || old_data.bio           },           false <- new_data == old_data do        change = Ecto.Changeset.change(user, new_data) -      Repo.update(change) +      User.update_and_set_cache(change)      else        _ ->          {:ok, user} diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 09265954a..d6a9d5779 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -297,12 +297,6 @@ defmodule Pleroma.Web.Router do      post("/account/update_profile_banner", TwitterAPI.Controller, :update_banner)      post("/qvitter/update_background_image", TwitterAPI.Controller, :update_background) -    post( -      "/account/most_recent_notification", -      TwitterAPI.Controller, -      :update_most_recent_notification -    ) -      get("/statuses/home_timeline", TwitterAPI.Controller, :friends_timeline)      get("/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline)      get("/statuses/mentions", TwitterAPI.Controller, :mentions_timeline) diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 562ec3d9c..b98ece6c9 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -157,7 +157,7 @@ defmodule Pleroma.Web.Salmon do      |> Enum.filter(fn user -> user && !user.local end)    end -  defp send_to_user(%{info: %{"salmon" => salmon}}, feed, poster) do +  defp send_to_user(%{info: %{salmon: salmon}}, feed, poster) do      with {:ok, %{status_code: code}} <-             poster.(               salmon, @@ -185,7 +185,7 @@ defmodule Pleroma.Web.Salmon do    ]    def publish(user, activity, poster \\ &@httpoison.post/4) -  def publish(%{info: %{"keys" => keys}} = user, %{data: %{"type" => type}} = activity, poster) +  def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity, poster)        when type in @supported_activities do      feed = ActivityRepresenter.to_simple_form(activity, user, true) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 306598157..99b8b7063 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -188,7 +188,7 @@ defmodule Pleroma.Web.Streamer do        # Get the current user so we have up-to-date blocks etc.        if socket.assigns[:user] do          user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) -        blocks = user.info["blocks"] || [] +        blocks = user.info.blocks || []          parent = Object.normalize(item.data["object"]) @@ -206,7 +206,7 @@ defmodule Pleroma.Web.Streamer do        # Get the current user so we have up-to-date blocks etc.        if socket.assigns[:user] do          user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) -        blocks = user.info["blocks"] || [] +        blocks = user.info.blocks || []          unless item.actor in blocks do            send(socket.transport_pid, {:text, represent_update(item, user)}) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 6223580e1..39a2974bb 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -148,7 +148,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do      cond do        registrations_open || (!is_nil(token) && !token.used) -> -        changeset = User.register_changeset(%User{}, params) +        changeset = User.register_changeset(%User{info: %{}}, params)          with {:ok, user} <- Repo.insert(changeset) do            !registrations_open && UserInviteToken.mark_as_used(token.token) @@ -279,14 +279,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do    def get_external_profile(for_user, uri) do      with %User{} = user <- User.get_or_fetch(uri) do -      spawn(fn -> -        with url <- user.info["topic"], -             {:ok, %{body: body}} <- -               @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do -          OStatus.handle_incoming(body) -        end -      end) -        {:ok, UserView.render("show.json", %{user: user, for: for_user})}      else        _e -> diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 064730867..ff644dd79 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -300,9 +300,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def update_banner(%{assigns: %{user: user}} = conn, params) do      with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner), -         new_info <- Map.put(user.info, "banner", object.data), -         change <- User.info_changeset(user, %{info: new_info}), -         {:ok, user} <- User.update_and_set_cache(change) do +         new_info <- %{"banner" => object.data}, +         info_cng <- User.Info.profile_update(user.info, new_info), +         changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), +         {:ok, user} <- User.update_and_set_cache(changeset) do        CommonAPI.update(user)        %{"url" => [%{"href" => href} | _]} = object.data        response = %{url: href} |> Jason.encode!() @@ -314,9 +315,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def update_background(%{assigns: %{user: user}} = conn, params) do      with {:ok, object} <- ActivityPub.upload(params, type: :background), -         new_info <- Map.put(user.info, "background", object.data), -         change <- User.info_changeset(user, %{info: new_info}), -         {:ok, _user} <- User.update_and_set_cache(change) do +         new_info <- %{"background" => object.data}, +         info_cng <- User.Info.profile_update(user.info, new_info), +         changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), +         {:ok, _user} <- User.update_and_set_cache(changeset) do        %{"url" => [%{"href" => href} | _]} = object.data        response = %{url: href} |> Jason.encode!() @@ -338,20 +340,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      end    end -  def update_most_recent_notification(%{assigns: %{user: user}} = conn, %{"id" => id}) do -    with id when is_number(id) <- String.to_integer(id), -         info <- user.info, -         mrn <- max(id, user.info["most_recent_notification"] || 0), -         updated_info <- Map.put(info, "most_recent_notification", mrn), -         changeset <- User.info_changeset(user, %{info: updated_info}), -         {:ok, _user} <- User.update_and_set_cache(changeset) do -      conn -      |> json_reply(200, Jason.encode!(mrn)) -    else -      _e -> bad_request_reply(conn, "Can't update.") -    end -  end -    def followers(conn, params) do      with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),           {:ok, followers} <- User.get_followers(user) do @@ -439,67 +427,52 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      json(conn, [])    end -  def update_profile(%{assigns: %{user: user}} = conn, params) do -    params = -      if bio = params["description"] 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) - -        bio_html = CommonUtils.format_input(bio, mentions, tags, "text/plain") -        Map.put(params, "bio", bio_html |> Formatter.emojify(emoji)) -      else -        params -      end - -    user = -      if locked = params["locked"] do -        with locked <- locked == "true", -             new_info <- Map.put(user.info, "locked", locked), -             change <- User.info_changeset(user, %{info: new_info}), -             {:ok, user} <- User.update_and_set_cache(change) do -          user +  defp build_info_cng(user, params) do +    info_params = +      ["no_rich_text", "locked"] +      |> Enum.reduce(%{}, fn key, res -> +        if value = params[key] do +          Map.put(res, key, value == "true")          else -          _e -> user +          res          end -      else -        user -      end +      end) -    user = -      if no_rich_text = params["no_rich_text"] do -        with no_rich_text <- no_rich_text == "true", -             new_info <- Map.put(user.info, "no_rich_text", no_rich_text), -             change <- User.info_changeset(user, %{info: new_info}), -             {:ok, user} <- User.update_and_set_cache(change) do -          user -        else -          _e -> user -        end +    info_params = +      if value = params["default_scope"] do +        Map.put(info_params, "default_scope", value)        else -        user +        info_params        end -    user = -      if default_scope = params["default_scope"] do -        with new_info <- Map.put(user.info, "default_scope", default_scope), -             change <- User.info_changeset(user, %{info: new_info}), -             {:ok, user} <- User.update_and_set_cache(change) do -          user -        else -          _e -> user -        end -      else -        user -      end +    User.Info.profile_update(user.info, info_params) +  end + +  defp add_profile_emoji(user, params) do +    if bio = params["description"] 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) + +      bio_html = CommonUtils.format_input(bio, mentions, tags, "text/plain") +      Map.put(params, "bio", bio_html |> Formatter.emojify(emoji)) +    else +      params +    end +  end + +  def update_profile(%{assigns: %{user: user}} = conn, params) do +    params = add_profile_emoji(user, params) +    info_cng = build_info_cng(user, params)      with changeset <- User.update_changeset(user, params), +         changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),           {:ok, user} <- User.update_and_set_cache(changeset) do        CommonAPI.update(user)        render(conn, UserView, "user.json", %{user: user, for: user}) diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index a100a1127..b78024ed7 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do      user_info = User.get_cached_user_info(user)      emoji = -      (user.info["source_data"]["tag"] || []) +      (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} @@ -40,7 +40,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do      # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``.      # For example: [{"name": "Pronoun", "value": "she/her"}, …]      fields = -      (user.info["source_data"]["attachment"] || []) +      (user.info.source_data["attachment"] || [])        |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)        |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) @@ -66,17 +66,17 @@ defmodule Pleroma.Web.TwitterAPI.UserView do        "profile_image_url_profile_size" => image,        "profile_image_url_original" => image,        "rights" => %{ -        "delete_others_notice" => !!user.info["is_moderator"] +        "delete_others_notice" => !!user.info.is_moderator        },        "screen_name" => user.nickname,        "statuses_count" => user_info[:note_count],        "statusnet_profile_url" => user.ap_id,        "cover_photo" => User.banner_url(user) |> MediaProxy.url(), -      "background_image" => image_url(user.info["background"]) |> MediaProxy.url(), +      "background_image" => image_url(user.info.background) |> MediaProxy.url(),        "is_local" => user.local, -      "locked" => !!user.info["locked"], -      "default_scope" => user.info["default_scope"] || "public", -      "no_rich_text" => user.info["no_rich_text"] || false, +      "locked" => user.info.locked, +      "default_scope" => user.info.default_scope, +      "no_rich_text" => user.info.no_rich_text,        "fields" => fields      } diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 9f554d286..eaee3a8c6 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -45,7 +45,7 @@ defmodule Pleroma.Web.WebFinger do    def represent_user(user, "JSON") do      {:ok, user} = ensure_keys_present(user) -    {:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"]) +    {:ok, _private, public} = Salmon.keys_from_pem(user.info.keys)      magic_key = Salmon.encode_key(public)      %{ @@ -83,7 +83,7 @@ defmodule Pleroma.Web.WebFinger do    def represent_user(user, "XML") do      {:ok, user} = ensure_keys_present(user) -    {:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"]) +    {:ok, _private, public} = Salmon.keys_from_pem(user.info.keys)      magic_key = Salmon.encode_key(public)      { @@ -113,16 +113,22 @@ defmodule Pleroma.Web.WebFinger do    # This seems a better fit in Salmon    def ensure_keys_present(user) do -    info = user.info || %{} +    info = user.info -    if info["keys"] do +    if info.keys do        {:ok, user}      else        {:ok, pem} = Salmon.generate_rsa_pem() -      info = Map.put(info, "keys", pem) -      Ecto.Changeset.change(user, info: info) -      |> User.update_and_set_cache() +      info_cng = +        info +        |> Pleroma.User.Info.set_keys(pem) + +      cng = +        Ecto.Changeset.change(user) +        |> Ecto.Changeset.put_embed(:info, info_cng) + +      User.update_and_set_cache(cng)      end    end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 396dcf045..905d8d658 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -146,7 +146,7 @@ defmodule Pleroma.Web.Websub do    end    def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do -    topic = subscribed.info["topic"] +    topic = subscribed.info.topic      # FIXME: Race condition, use transactions      {:ok, subscription} =        with subscription when not is_nil(subscription) <- @@ -158,7 +158,7 @@ defmodule Pleroma.Web.Websub do          _e ->            subscription = %WebsubClientSubscription{              topic: topic, -            hub: subscribed.info["hub"], +            hub: subscribed.info.hub,              subscribers: [subscriber.ap_id],              state: "requested",              secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64(),  | 
