Merge branch 'validate-user-info' into 'develop'

Validate user info

See merge request pleroma/pleroma!465
This commit is contained in:
kaniini 2018-12-01 22:11:52 +00:00
commit 371d96b1da
46 changed files with 640 additions and 411 deletions

View File

@ -116,8 +116,8 @@ def add_user_links({subs, text}, mentions) do
subs ++ subs ++
Enum.map(mentions, fn {match, %User{ap_id: ap_id, info: info}, uuid} -> Enum.map(mentions, fn {match, %User{ap_id: ap_id, info: info}, uuid} ->
ap_id = ap_id =
if is_binary(info["source_data"]["url"]) do if is_binary(info.source_data["url"]) do
info["source_data"]["url"] info.source_data["url"]
else else
ap_id ap_id
end end

View File

@ -20,7 +20,7 @@ def call(conn, _) do
with token when not is_nil(token) <- token, with token when not is_nil(token) <- token,
%Token{user_id: user_id} <- Repo.get_by(Token, token: token), %Token{user_id: user_id} <- Repo.get_by(Token, token: token),
%User{} = user <- Repo.get(User, user_id), %User{} = user <- Repo.get(User, user_id),
false <- !!user.info["deactivated"] do false <- !!user.info.deactivated do
conn conn
|> assign(:user, user) |> assign(:user, user)
else else

View File

@ -6,7 +6,7 @@ def init(options) do
options options
end end
def call(%{assigns: %{user: %User{info: %{"deactivated" => true}}}} = conn, _) do def call(%{assigns: %{user: %User{info: %{deactivated: true}}}} = conn, _) do
conn conn
|> assign(:user, nil) |> assign(:user, nil)
end end

View File

@ -6,7 +6,7 @@ def init(options) do
options options
end end
def call(%{assigns: %{user: %User{info: %{"is_admin" => true}}}} = conn, _) do def call(%{assigns: %{user: %User{info: %{is_admin: true}}}} = conn, _) do
conn conn
end end

View File

@ -19,11 +19,11 @@ defmodule Pleroma.User do
field(:ap_id, :string) field(:ap_id, :string)
field(:avatar, :map) field(:avatar, :map)
field(:local, :boolean, default: true) field(:local, :boolean, default: true)
field(:info, :map, default: %{})
field(:follower_address, :string) field(:follower_address, :string)
field(:search_distance, :float, virtual: true) field(:search_distance, :float, virtual: true)
field(:last_refreshed_at, :naive_datetime) field(:last_refreshed_at, :naive_datetime)
has_many(:notifications, Notification) has_many(:notifications, Notification)
embeds_one(:info, Pleroma.User.Info)
timestamps() timestamps()
end end
@ -36,13 +36,13 @@ def avatar_url(user) do
end end
def banner_url(user) do def banner_url(user) do
case user.info["banner"] do case user.info.banner do
%{"url" => [%{"href" => href} | _]} -> href %{"url" => [%{"href" => href} | _]} -> href
_ -> "#{Web.base_url()}/images/banner.png" _ -> "#{Web.base_url()}/images/banner.png"
end end
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(%User{ap_id: ap_id}), do: ap_id
def profile_url(_), do: nil def profile_url(_), do: nil
@ -61,9 +61,7 @@ def follow_changeset(struct, params \\ %{}) do
end end
def info_changeset(struct, params \\ %{}) do def info_changeset(struct, params \\ %{}) do
struct raise "NOT VALID ANYMORE"
|> cast(params, [:info])
|> validate_required([:info])
end end
def user_info(%User{} = user) do def user_info(%User{} = user) do
@ -71,27 +69,34 @@ def user_info(%User{} = user) do
%{ %{
following_count: length(user.following) - oneself, following_count: length(user.following) - oneself,
note_count: user.info["note_count"] || 0, note_count: user.info.note_count,
follower_count: user.info["follower_count"] || 0, follower_count: user.info.follower_count,
locked: user.info["locked"] || false, locked: user.info.locked,
default_scope: user.info["default_scope"] || "public" default_scope: user.info.default_scope
} }
end 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])?)*$/ @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 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 = changes =
%User{} %User{}
|> cast(params, [:bio, :name, :ap_id, :nickname, :info, :avatar]) |> cast(params, [:bio, :name, :ap_id, :nickname, :avatar])
|> validate_required([:name, :ap_id]) |> validate_required([:name, :ap_id])
|> unique_constraint(:nickname) |> unique_constraint(:nickname)
|> validate_format(:nickname, @email_regex) |> validate_format(:nickname, @email_regex)
|> validate_length(:bio, max: 5000) |> validate_length(:bio, max: 5000)
|> validate_length(:name, max: 100) |> validate_length(:name, max: 100)
|> put_change(:local, false) |> put_change(:local, false)
|> put_embed(:info, info_cng)
if changes.valid? do if changes.valid? do
case changes.changes[:info]["source_data"] do case info_cng.changes[:source_data] do
%{"followers" => followers} -> %{"followers" => followers} ->
changes changes
|> put_change(:follower_address, followers) |> put_change(:follower_address, followers)
@ -109,7 +114,7 @@ def remote_user_creation(params) do
def update_changeset(struct, params \\ %{}) do def update_changeset(struct, params \\ %{}) do
struct struct
|> cast(params, [:bio, :name]) |> cast(params, [:bio, :name, :avatar])
|> unique_constraint(:nickname) |> unique_constraint(:nickname)
|> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/) |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/)
|> validate_length(:bio, max: 5000) |> validate_length(:bio, max: 5000)
@ -121,12 +126,17 @@ def upgrade_changeset(struct, params \\ %{}) do
params params
|> Map.put(:last_refreshed_at, NaiveDateTime.utc_now()) |> Map.put(:last_refreshed_at, NaiveDateTime.utc_now())
info_cng =
struct.info
|> User.Info.user_upgrade(params[:info])
struct 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) |> unique_constraint(:nickname)
|> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/) |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/)
|> validate_length(:bio, max: 5000) |> validate_length(:bio, max: 5000)
|> validate_length(:name, max: 100) |> validate_length(:name, max: 100)
|> put_embed(:info, info_cng)
end end
def password_update_changeset(struct, params) do def password_update_changeset(struct, params) do
@ -191,7 +201,7 @@ def needs_update?(%User{local: false} = user) do
def needs_update?(_), do: true 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} {:ok, follower}
end end
@ -222,7 +232,7 @@ def follow(%User{} = follower, %User{info: info} = followed) do
ap_followers = followed.follower_address ap_followers = followed.follower_address
cond do 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."} {:error, "Could not follow user: #{followed.nickname} is already on your list."}
deny_follow_blocked and blocks?(followed, follower) -> deny_follow_blocked and blocks?(followed, follower) ->
@ -274,7 +284,7 @@ def following?(%User{} = follower, %User{} = followed) do
end end
def locked?(%User{} = user) do def locked?(%User{} = user) do
user.info["locked"] || false user.info.locked || false
end end
def get_by_ap_id(ap_id) do def get_by_ap_id(ap_id) do
@ -411,22 +421,23 @@ def get_follow_requests(%User{} = user) do
end end
def increase_note_count(%User{} = user) do def increase_note_count(%User{} = user) do
note_count = (user.info["note_count"] || 0) + 1 info_cng = User.Info.add_to_note_count(user.info, 1)
new_info = Map.put(user.info, "note_count", 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 end
def decrease_note_count(%User{} = user) do def decrease_note_count(%User{} = user) do
note_count = user.info["note_count"] || 0 info_cng = User.Info.add_to_note_count(user.info, -1)
note_count = if note_count <= 0, do: 0, else: note_count - 1
new_info = Map.put(user.info, "note_count", 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 end
def update_note_count(%User{} = user) do def update_note_count(%User{} = user) do
@ -439,11 +450,13 @@ def update_note_count(%User{} = user) do
note_count = Repo.one(note_count_query) 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 end
def update_follower_count(%User{} = user) do def update_follower_count(%User{} = user) do
@ -457,11 +470,15 @@ def update_follower_count(%User{} = user) do
follower_count = Repo.one(follower_count_query) 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 end
def get_users_from_set_query(ap_ids, false) do def get_users_from_set_query(ap_ids, false) do
@ -545,12 +562,15 @@ def block(blocker, %User{ap_id: ap_id} = blocked) do
unfollow(blocked, blocker) unfollow(blocked, blocker)
end end
blocks = blocker.info["blocks"] || [] info_cng =
new_blocks = Enum.uniq([ap_id | blocks]) blocker.info
new_info = Map.put(blocker.info, "blocks", new_blocks) |> User.Info.add_to_block(ap_id)
cs = User.info_changeset(blocker, %{info: new_info}) cng =
update_and_set_cache(cs) change(blocker)
|> put_embed(:info, info_cng)
update_and_set_cache(cng)
end end
# helper to handle the block given only an actor's AP id # helper to handle the block given only an actor's AP id
@ -558,18 +578,21 @@ def block(blocker, %{ap_id: ap_id}) do
block(blocker, User.get_by_ap_id(ap_id)) block(blocker, User.get_by_ap_id(ap_id))
end end
def unblock(user, %{ap_id: ap_id}) do def unblock(blocker, %{ap_id: ap_id}) do
blocks = user.info["blocks"] || [] info_cng =
new_blocks = List.delete(blocks, ap_id) blocker.info
new_info = Map.put(user.info, "blocks", new_blocks) |> User.Info.remove_from_block(ap_id)
cs = User.info_changeset(user, %{info: new_info}) cng =
update_and_set_cache(cs) change(blocker)
|> put_embed(:info, info_cng)
update_and_set_cache(cng)
end end
def blocks?(user, %{ap_id: ap_id}) do def blocks?(user, %{ap_id: ap_id}) do
blocks = user.info["blocks"] || [] blocks = user.info.blocks
domain_blocks = user.info["domain_blocks"] || [] domain_blocks = user.info.domain_blocks
%{host: host} = URI.parse(ap_id) %{host: host} = URI.parse(ap_id)
Enum.member?(blocks, ap_id) || Enum.member?(blocks, ap_id) ||
@ -579,21 +602,27 @@ def blocks?(user, %{ap_id: ap_id}) do
end end
def block_domain(user, domain) do def block_domain(user, domain) do
domain_blocks = user.info["domain_blocks"] || [] info_cng =
new_blocks = Enum.uniq([domain | domain_blocks]) user.info
new_info = Map.put(user.info, "domain_blocks", new_blocks) |> User.Info.add_to_domain_block(domain)
cs = User.info_changeset(user, %{info: new_info}) cng =
update_and_set_cache(cs) change(user)
|> put_embed(:info, info_cng)
update_and_set_cache(cng)
end end
def unblock_domain(user, domain) do def unblock_domain(user, domain) do
blocks = user.info["domain_blocks"] || [] info_cng =
new_blocks = List.delete(blocks, domain) user.info
new_info = Map.put(user.info, "domain_blocks", new_blocks) |> User.Info.remove_from_domain_block(domain)
cs = User.info_changeset(user, %{info: new_info}) cng =
update_and_set_cache(cs) change(user)
|> put_embed(:info, info_cng)
update_and_set_cache(cng)
end end
def local_user_query() do def local_user_query() do
@ -613,9 +642,13 @@ def moderator_user_query() do
end end
def deactivate(%User{} = user, status \\ true) do def deactivate(%User{} = user, status \\ true) do
new_info = Map.put(user.info, "deactivated", status) info_cng = User.Info.set_activation_status(user.info, status)
cs = User.info_changeset(user, %{info: new_info})
update_and_set_cache(cs) cng =
change(user)
|> put_embed(:info, info_cng)
update_and_set_cache(cng)
end end
def delete(%User{} = user) do def delete(%User{} = user) do
@ -649,7 +682,7 @@ def delete(%User{} = user) do
{:ok, user} {:ok, user}
end 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 Pleroma.HTML.Scrubber.TwitterText
end end
@ -683,7 +716,7 @@ def get_or_create_instance_user do
user user
else else
changes = changes =
%User{} %User{info: %User.Info{}}
|> cast(%{}, [:ap_id, :nickname, :local]) |> cast(%{}, [:ap_id, :nickname, :local])
|> put_change(:ap_id, relay_uri) |> put_change(:ap_id, relay_uri)
|> put_change(:nickname, nil) |> put_change(:nickname, nil)
@ -697,7 +730,7 @@ def get_or_create_instance_user do
# AP style # AP style
def public_key_from_info(%{ def public_key_from_info(%{
"source_data" => %{"publicKey" => %{"publicKeyPem" => public_key_pem}} source_data: %{"publicKey" => %{"publicKeyPem" => public_key_pem}}
}) do }) do
key = key =
:public_key.pem_decode(public_key_pem) :public_key.pem_decode(public_key_pem)
@ -708,7 +741,7 @@ def public_key_from_info(%{
end end
# OStatus Magic Key # 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)} {:ok, Pleroma.Web.Salmon.decode_key(magic_key)}
end end
@ -730,11 +763,12 @@ def insert_or_update_user(data) do
|> Map.put(:name, blank?(data[:name]) || data[:nickname]) |> Map.put(:name, blank?(data[:name]) || data[:nickname])
cs = User.remote_user_creation(data) cs = User.remote_user_creation(data)
Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname) Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname)
end end
def ap_enabled?(%User{local: true}), do: true 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 ap_enabled?(_), do: false
def get_or_fetch(uri_or_nickname) do def get_or_fetch(uri_or_nickname) do

164
lib/pleroma/user/info.ex Normal file
View File

@ -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

View File

@ -42,7 +42,7 @@ defp get_recipients(data) do
defp check_actor_is_active(actor) do defp check_actor_is_active(actor) do
if not is_nil(actor) do if not is_nil(actor) do
with user <- User.get_cached_by_ap_id(actor), with user <- User.get_cached_by_ap_id(actor),
false <- !!user.info["deactivated"] do false <- user.info.deactivated do
:ok :ok
else else
_e -> :reject _e -> :reject
@ -509,8 +509,8 @@ defp restrict_recent(query, _) do
end end
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
blocks = info["blocks"] || [] blocks = info.blocks || []
domain_blocks = info["domain_blocks"] || [] domain_blocks = info.domain_blocks || []
from( from(
activity in query, activity in query,
@ -676,7 +676,7 @@ def publish(actor, activity) do
remote_inboxes = remote_inboxes =
(Pleroma.Web.Salmon.remote_users(activity) ++ followers) (Pleroma.Web.Salmon.remote_users(activity) ++ followers)
|> Enum.filter(fn user -> User.ap_enabled?(user) end) |> 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"] (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
end) end)
|> Enum.uniq() |> Enum.uniq()

View File

@ -447,7 +447,7 @@ def handle_incoming(
update_data = update_data =
new_user_data new_user_data
|> Map.take([:name, :bio, :avatar]) |> Map.take([:name, :bio, :avatar])
|> Map.put(:info, Map.merge(actor.info, %{"banner" => banner, "locked" => locked})) |> Map.put(:info, %{"banner" => banner, "locked" => locked})
actor actor
|> User.upgrade_changeset(update_data) |> User.upgrade_changeset(update_data)
@ -850,10 +850,6 @@ defp user_upgrade_task(user) do
def upgrade_user_from_ap_id(ap_id, async \\ true) do def upgrade_user_from_ap_id(ap_id, async \\ true) do
with %User{local: false} = user <- User.get_by_ap_id(ap_id), 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 {: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) already_ap = User.ap_enabled?(user)
{:ok, user} = {:ok, user} =

View File

@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
# the instance itself is not a Person, but instead an Application # the instance itself is not a Person, but instead an Application
def render("user.json", %{user: %{nickname: nil} = user}) do def render("user.json", %{user: %{nickname: nil} = user}) do
{:ok, user} = WebFinger.ensure_keys_present(user) {: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_entry_encode(:SubjectPublicKeyInfo, public_key)
public_key = :public_key.pem_encode([public_key]) public_key = :public_key.pem_encode([public_key])
@ -40,7 +40,7 @@ def render("user.json", %{user: %{nickname: nil} = user}) do
def render("user.json", %{user: user}) do def render("user.json", %{user: user}) do
{:ok, user} = WebFinger.ensure_keys_present(user) {: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_entry_encode(:SubjectPublicKeyInfo, public_key)
public_key = :public_key.pem_encode([public_key]) public_key = :public_key.pem_encode([public_key])
@ -55,7 +55,7 @@ def render("user.json", %{user: user}) do
"name" => user.name, "name" => user.name,
"summary" => user.bio, "summary" => user.bio,
"url" => user.ap_id, "url" => user.ap_id,
"manuallyApprovesFollowers" => user.info["locked"] || false, "manuallyApprovesFollowers" => user.info.locked,
"publicKey" => %{ "publicKey" => %{
"id" => "#{user.ap_id}#main-key", "id" => "#{user.ap_id}#main-key",
"owner" => user.ap_id, "owner" => user.ap_id,
@ -72,7 +72,7 @@ def render("user.json", %{user: user}) do
"type" => "Image", "type" => "Image",
"url" => User.banner_url(user) "url" => User.banner_url(user)
}, },
"tag" => user.info["source_data"]["tag"] || [] "tag" => user.info.source_data["tag"] || []
} }
|> Map.merge(Utils.make_json_ld_header()) |> Map.merge(Utils.make_json_ld_header())
end end

View File

@ -45,21 +45,29 @@ def right_add(conn, %{"permission_group" => permission_group, "nickname" => nick
user = User.get_by_nickname(nickname) user = User.get_by_nickname(nickname)
info = info =
user.info %{}
|> Map.put("is_" <> permission_group, true) |> 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) {:ok, user} = User.update_and_set_cache(cng)
conn conn
|> json(user.info) |> json(info)
end end
def right_get(conn, %{"nickname" => nickname}) do def right_get(conn, %{"nickname" => nickname}) do
user = User.get_by_nickname(nickname) user = User.get_by_nickname(nickname)
conn conn
|> json(user.info) |> json(%{
is_moderator: user.info.is_moderator,
is_admin: user.info.is_admin
})
end end
def right_add(conn, _) do def right_add(conn, _) do
@ -84,14 +92,19 @@ def right_delete(
user = User.get_by_nickname(nickname) user = User.get_by_nickname(nickname)
info = info =
user.info %{}
|> Map.put("is_" <> permission_group, false) |> 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) {:ok, user} = User.update_and_set_cache(cng)
conn conn
|> json(user.info) |> json(info)
end end
end end

View File

@ -8,7 +8,7 @@ defmodule Pleroma.Web.CommonAPI do
def delete(activity_id, user) do def delete(activity_id, user) do
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id), with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
%Object{} = object <- Object.normalize(object_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} <- ActivityPub.delete(object) do
{:ok, delete} {:ok, delete}
end end
@ -135,12 +135,13 @@ def post(user, %{"status" => status} = data) do
end end
end end
# Updates the emojis for a user based on their profile
def update(user) do def update(user) do
user = user =
with emoji <- emoji_from_profile(user), with emoji <- emoji_from_profile(user),
source_data <- (user.info["source_data"] || %{}) |> Map.put("tag", emoji), source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji),
new_info <- Map.put(user.info, "source_data", source_data), info_cng <- Pleroma.User.Info.set_source_data(user.info, source_data),
change <- User.info_changeset(user, %{info: new_info}), change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
{:ok, user} <- User.update_and_set_cache(change) do {:ok, user} <- User.update_and_set_cache(change) do
user user
else else

View File

@ -65,7 +65,7 @@ def build_signing_string(headers, used_headers) do
end end
def sign(user, headers) do 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 {:ok, private_key, _} = Pleroma.Web.Salmon.keys_from_pem(keys) do
sigstring = build_signing_string(headers, Map.keys(headers)) sigstring = build_signing_string(headers, Map.keys(headers))

View File

@ -32,67 +32,55 @@ def create_app(conn, params) do
end end
end end
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
def update_credentials(%{assigns: %{user: user}} = conn, params) do def update_credentials(%{assigns: %{user: user}} = conn, params) do
original_user = user original_user = user
params = user_params =
if bio = params["note"] do %{}
Map.put(params, "bio", bio) |> add_if_present(params, "display_name", :name)
else |> add_if_present(params, "note", :bio)
params |> add_if_present(params, "avatar", :avatar, fn value ->
end with %Plug.Upload{} <- value,
{:ok, object} <- ActivityPub.upload(value, type: :avatar) do
params = {:ok, object.data}
if name = params["display_name"] do
Map.put(params, "name", name)
else
params
end
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
else else
_e -> user _ -> :error
end end
else end)
user
end
user = info_params =
if banner = params["header"] do %{}
with %Plug.Upload{} <- banner, |> add_if_present(params, "locked", :locked, fn value -> {:ok, value == "true"} end)
{:ok, object} <- ActivityPub.upload(banner, type: :banner), |> add_if_present(params, "header", :banner, fn value ->
new_info <- Map.put(user.info, "banner", object.data), with %Plug.Upload{} <- value,
change <- User.info_changeset(user, %{info: new_info}), {:ok, object} <- ActivityPub.upload(value, type: :banner) do
{:ok, user} <- User.update_and_set_cache(change) do {:ok, object.data}
user
else else
_e -> user _ -> :error
end end
else end)
user
end
user = info_cng = User.Info.mastodon_profile_update(user.info, info_params)
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
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 {:ok, user} <- User.update_and_set_cache(changeset) do
if original_user != user do if original_user != user do
CommonAPI.update(user) CommonAPI.update(user)
@ -644,7 +632,7 @@ def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
# TODO: Use proper query # TODO: Use proper query
def blocks(%{assigns: %{user: user}} = conn, _) do 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 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) res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
json(conn, res) json(conn, res)
@ -652,7 +640,7 @@ def blocks(%{assigns: %{user: user}} = conn, _) do
end end
def domain_blocks(%{assigns: %{user: %{info: info}}} = conn, _) do def domain_blocks(%{assigns: %{user: %{info: info}}} = conn, _) do
json(conn, info["domain_blocks"] || []) json(conn, info.domain_blocks || [])
end end
def block_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do def block_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
@ -900,11 +888,11 @@ def index(%{assigns: %{user: user}} = conn, _params) do
max_toot_chars: limit max_toot_chars: limit
}, },
rights: %{ rights: %{
delete_others_notice: !!user.info["is_moderator"] delete_others_notice: !!user.info.is_moderator
}, },
compose: %{ compose: %{
me: "#{user.id}", me: "#{user.id}",
default_privacy: user.info["default_scope"] || "public", default_privacy: user.info.default_scope,
default_sensitive: false default_sensitive: false
}, },
media_attachments: %{ media_attachments: %{
@ -924,7 +912,7 @@ def index(%{assigns: %{user: user}} = conn, _params) do
] ]
}, },
settings: settings:
Map.get(user.info, "settings") || Map.get(user.info, :settings) ||
%{ %{
onboarded: true, onboarded: true,
home: %{ home: %{

View File

@ -14,10 +14,10 @@ def render("account.json", %{user: user} = opts) do
image = User.avatar_url(user) |> MediaProxy.url() image = User.avatar_url(user) |> MediaProxy.url()
header = User.banner_url(user) |> MediaProxy.url() header = User.banner_url(user) |> MediaProxy.url()
user_info = User.user_info(user) 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 = emojis =
(user.info["source_data"]["tag"] || []) (user.info.source_data["tag"] || [])
|> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
|> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
%{ %{
@ -29,7 +29,7 @@ def render("account.json", %{user: user} = opts) do
end) end)
fields = fields =
(user.info["source_data"]["attachment"] || []) (user.info.source_data["attachment"] || [])
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)

View File

@ -226,25 +226,21 @@ def maybe_update_ostatus(doc, user) do
old_data = %{ old_data = %{
avatar: user.avatar, avatar: user.avatar,
bio: user.bio, bio: user.bio,
name: user.name, name: user.name
info: user.info
} }
with false <- user.local, with false <- user.local,
avatar <- make_avatar_object(doc), avatar <- make_avatar_object(doc),
bio <- string_from_xpath("//author[1]/summary", doc), bio <- string_from_xpath("//author[1]/summary", doc),
name <- string_from_xpath("//author[1]/poco:displayName", 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 <- %{ new_data <- %{
avatar: avatar || old_data.avatar, avatar: avatar || old_data.avatar,
name: name || old_data.name, name: name || old_data.name,
bio: bio || old_data.bio, bio: bio || old_data.bio
info: info || old_data.info
}, },
false <- new_data == old_data do false <- new_data == old_data do
change = Ecto.Changeset.change(user, new_data) change = Ecto.Changeset.change(user, new_data)
Repo.update(change) User.update_and_set_cache(change)
else else
_ -> _ ->
{:ok, user} {:ok, user}

View File

@ -297,12 +297,6 @@ defmodule Pleroma.Web.Router do
post("/account/update_profile_banner", TwitterAPI.Controller, :update_banner) post("/account/update_profile_banner", TwitterAPI.Controller, :update_banner)
post("/qvitter/update_background_image", TwitterAPI.Controller, :update_background) 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/home_timeline", TwitterAPI.Controller, :friends_timeline)
get("/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline) get("/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline)
get("/statuses/mentions", TwitterAPI.Controller, :mentions_timeline) get("/statuses/mentions", TwitterAPI.Controller, :mentions_timeline)

View File

@ -157,7 +157,7 @@ def remote_users(%{data: %{"to" => to} = data}) do
|> Enum.filter(fn user -> user && !user.local end) |> Enum.filter(fn user -> user && !user.local end)
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}} <- with {:ok, %{status_code: code}} <-
poster.( poster.(
salmon, salmon,
@ -185,7 +185,7 @@ defp send_to_user(_, _, _), do: nil
] ]
def publish(user, activity, poster \\ &@httpoison.post/4) 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 when type in @supported_activities do
feed = ActivityRepresenter.to_simple_form(activity, user, true) feed = ActivityRepresenter.to_simple_form(activity, user, true)

View File

@ -188,7 +188,7 @@ def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = ite
# Get the current user so we have up-to-date blocks etc. # Get the current user so we have up-to-date blocks etc.
if socket.assigns[:user] do if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) 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"]) parent = Object.normalize(item.data["object"])
@ -206,7 +206,7 @@ def push_to_socket(topics, topic, item) do
# Get the current user so we have up-to-date blocks etc. # Get the current user so we have up-to-date blocks etc.
if socket.assigns[:user] do if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) 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 unless item.actor in blocks do
send(socket.transport_pid, {:text, represent_update(item, user)}) send(socket.transport_pid, {:text, represent_update(item, user)})

View File

@ -148,7 +148,7 @@ def register_user(params) do
cond do cond do
registrations_open || (!is_nil(token) && !token.used) -> 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 with {:ok, user} <- Repo.insert(changeset) do
!registrations_open && UserInviteToken.mark_as_used(token.token) !registrations_open && UserInviteToken.mark_as_used(token.token)
@ -279,14 +279,6 @@ def conversation_id_to_context(id) do
def get_external_profile(for_user, uri) do def get_external_profile(for_user, uri) do
with %User{} = user <- User.get_or_fetch(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})} {:ok, UserView.render("show.json", %{user: user, for: for_user})}
else else
_e -> _e ->

View File

@ -300,9 +300,10 @@ def update_avatar(%{assigns: %{user: user}} = conn, params) do
def update_banner(%{assigns: %{user: user}} = conn, params) do def update_banner(%{assigns: %{user: user}} = conn, params) do
with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner), with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
new_info <- Map.put(user.info, "banner", object.data), new_info <- %{"banner" => object.data},
change <- User.info_changeset(user, %{info: new_info}), info_cng <- User.Info.profile_update(user.info, new_info),
{:ok, user} <- User.update_and_set_cache(change) do changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
{:ok, user} <- User.update_and_set_cache(changeset) do
CommonAPI.update(user) CommonAPI.update(user)
%{"url" => [%{"href" => href} | _]} = object.data %{"url" => [%{"href" => href} | _]} = object.data
response = %{url: href} |> Jason.encode!() response = %{url: href} |> Jason.encode!()
@ -314,9 +315,10 @@ def update_banner(%{assigns: %{user: user}} = conn, params) do
def update_background(%{assigns: %{user: user}} = conn, params) do def update_background(%{assigns: %{user: user}} = conn, params) do
with {:ok, object} <- ActivityPub.upload(params, type: :background), with {:ok, object} <- ActivityPub.upload(params, type: :background),
new_info <- Map.put(user.info, "background", object.data), new_info <- %{"background" => object.data},
change <- User.info_changeset(user, %{info: new_info}), info_cng <- User.Info.profile_update(user.info, new_info),
{:ok, _user} <- User.update_and_set_cache(change) do 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 %{"url" => [%{"href" => href} | _]} = object.data
response = %{url: href} |> Jason.encode!() response = %{url: href} |> Jason.encode!()
@ -338,20 +340,6 @@ def external_profile(%{assigns: %{user: current_user}} = conn, %{"profileurl" =>
end end
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 def followers(conn, params) do
with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params), with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
{:ok, followers} <- User.get_followers(user) do {:ok, followers} <- User.get_followers(user) do
@ -439,67 +427,52 @@ def raw_empty_array(conn, _params) do
json(conn, []) json(conn, [])
end end
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
res
end
end)
info_params =
if value = params["default_scope"] do
Map.put(info_params, "default_scope", value)
else
info_params
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 def update_profile(%{assigns: %{user: user}} = conn, params) do
params = params = add_profile_emoji(user, params)
if bio = params["description"] do info_cng = build_info_cng(user, params)
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
else
_e -> user
end
else
user
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
else
user
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
with changeset <- User.update_changeset(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 {:ok, user} <- User.update_and_set_cache(changeset) do
CommonAPI.update(user) CommonAPI.update(user)
render(conn, UserView, "user.json", %{user: user, for: user}) render(conn, UserView, "user.json", %{user: user, for: user})

View File

@ -31,7 +31,7 @@ def render("user.json", %{user: user = %User{}} = assigns) do
user_info = User.get_cached_user_info(user) user_info = User.get_cached_user_info(user)
emoji = emoji =
(user.info["source_data"]["tag"] || []) (user.info.source_data["tag"] || [])
|> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
|> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
{String.trim(name, ":"), url} {String.trim(name, ":"), url}
@ -40,7 +40,7 @@ def render("user.json", %{user: user = %User{}} = assigns) do
# ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``.
# For example: [{"name": "Pronoun", "value": "she/her"}, …] # For example: [{"name": "Pronoun", "value": "she/her"}, …]
fields = fields =
(user.info["source_data"]["attachment"] || []) (user.info.source_data["attachment"] || [])
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
@ -66,17 +66,17 @@ def render("user.json", %{user: user = %User{}} = assigns) do
"profile_image_url_profile_size" => image, "profile_image_url_profile_size" => image,
"profile_image_url_original" => image, "profile_image_url_original" => image,
"rights" => %{ "rights" => %{
"delete_others_notice" => !!user.info["is_moderator"] "delete_others_notice" => !!user.info.is_moderator
}, },
"screen_name" => user.nickname, "screen_name" => user.nickname,
"statuses_count" => user_info[:note_count], "statuses_count" => user_info[:note_count],
"statusnet_profile_url" => user.ap_id, "statusnet_profile_url" => user.ap_id,
"cover_photo" => User.banner_url(user) |> MediaProxy.url(), "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, "is_local" => user.local,
"locked" => !!user.info["locked"], "locked" => user.info.locked,
"default_scope" => user.info["default_scope"] || "public", "default_scope" => user.info.default_scope,
"no_rich_text" => user.info["no_rich_text"] || false, "no_rich_text" => user.info.no_rich_text,
"fields" => fields "fields" => fields
} }

View File

@ -45,7 +45,7 @@ def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do
def represent_user(user, "JSON") do def represent_user(user, "JSON") do
{:ok, user} = ensure_keys_present(user) {: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) magic_key = Salmon.encode_key(public)
%{ %{
@ -83,7 +83,7 @@ def represent_user(user, "JSON") do
def represent_user(user, "XML") do def represent_user(user, "XML") do
{:ok, user} = ensure_keys_present(user) {: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) magic_key = Salmon.encode_key(public)
{ {
@ -113,16 +113,22 @@ def represent_user(user, "XML") do
# This seems a better fit in Salmon # This seems a better fit in Salmon
def ensure_keys_present(user) do def ensure_keys_present(user) do
info = user.info || %{} info = user.info
if info["keys"] do if info.keys do
{:ok, user} {:ok, user}
else else
{:ok, pem} = Salmon.generate_rsa_pem() {:ok, pem} = Salmon.generate_rsa_pem()
info = Map.put(info, "keys", pem)
Ecto.Changeset.change(user, info: info) info_cng =
|> User.update_and_set_cache() 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
end end

View File

@ -146,7 +146,7 @@ defp valid_topic(%{"hub.topic" => topic}, user) do
end end
def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do
topic = subscribed.info["topic"] topic = subscribed.info.topic
# FIXME: Race condition, use transactions # FIXME: Race condition, use transactions
{:ok, subscription} = {:ok, subscription} =
with subscription when not is_nil(subscription) <- with subscription when not is_nil(subscription) <-
@ -158,7 +158,7 @@ def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do
_e -> _e ->
subscription = %WebsubClientSubscription{ subscription = %WebsubClientSubscription{
topic: topic, topic: topic,
hub: subscribed.info["hub"], hub: subscribed.info.hub,
subscribers: [subscriber.ap_id], subscribers: [subscriber.ap_id],
state: "requested", state: "requested",
secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64(), secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64(),

View File

@ -0,0 +1,7 @@
defmodule Pleroma.Repo.Migrations.AddUUIDExtension do
use Ecto.Migration
def change do
execute("create extension if not exists \"uuid-ossp\"")
end
end

View File

@ -0,0 +1,7 @@
defmodule Pleroma.Repo.Migrations.AddUUIDsToUserInfo do
use Ecto.Migration
def change do
execute("update users set info = jsonb_set(info, '{\"id\"}', to_jsonb(uuid_generate_v4()))")
end
end

View File

@ -110,7 +110,7 @@ test "gives a replacement for user links" do
archaeme = archaeme =
insert(:user, %{ insert(:user, %{
nickname: "archaeme", nickname: "archaeme",
info: %{"source_data" => %{"url" => "https://archeme/@archaeme"}} info: %Pleroma.User.Info{source_data: %{"url" => "https://archeme/@archaeme"}}
}) })
archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"}) archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"})

View File

@ -13,7 +13,7 @@ test "doesn't do anything if the user isn't set", %{conn: conn} do
end end
test "with a user that is deactivated, it removes that user", %{conn: conn} do test "with a user that is deactivated, it removes that user", %{conn: conn} do
user = insert(:user, info: %{"deactivated" => true}) user = insert(:user, info: %{deactivated: true})
conn = conn =
conn conn

View File

@ -5,7 +5,7 @@ defmodule Pleroma.Plugs.UserIsAdminPlugTest do
import Pleroma.Factory import Pleroma.Factory
test "accepts a user that is admin", %{conn: conn} do test "accepts a user that is admin", %{conn: conn} do
user = insert(:user, info: %{"is_admin" => true}) user = insert(:user, info: %{is_admin: true})
conn = conn =
build_conn() build_conn()

View File

@ -7,7 +7,8 @@ def user_factory do
email: sequence(:email, &"user#{&1}@example.com"), email: sequence(:email, &"user#{&1}@example.com"),
nickname: sequence(:nickname, &"nick#{&1}"), nickname: sequence(:nickname, &"nick#{&1}"),
password_hash: Comeonin.Pbkdf2.hashpwsalt("test"), password_hash: Comeonin.Pbkdf2.hashpwsalt("test"),
bio: sequence(:bio, &"Tester Number #{&1}") bio: sequence(:bio, &"Tester Number #{&1}"),
info: %{}
} }
%{ %{

View File

@ -34,14 +34,14 @@ test "follow takes a user and another user" do
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
followed = User.get_by_ap_id(followed.ap_id) followed = User.get_by_ap_id(followed.ap_id)
assert followed.info["follower_count"] == 1 assert followed.info.follower_count == 1
assert User.ap_followers(followed) in user.following assert User.ap_followers(followed) in user.following
end end
test "can't follow a deactivated users" do test "can't follow a deactivated users" do
user = insert(:user) user = insert(:user)
followed = insert(:user, info: %{"deactivated" => true}) followed = insert(:user, info: %{deactivated: true})
{:error, _} = User.follow(user, followed) {:error, _} = User.follow(user, followed)
end end
@ -56,8 +56,8 @@ test "can't follow a user who blocked us" do
end end
test "local users do not automatically follow local locked accounts" do test "local users do not automatically follow local locked accounts" do
follower = insert(:user, info: %{"locked" => true}) follower = insert(:user, info: %{locked: true})
followed = insert(:user, info: %{"locked" => true}) followed = insert(:user, info: %{locked: true})
{:ok, follower} = User.maybe_direct_follow(follower, followed) {:ok, follower} = User.maybe_direct_follow(follower, followed)
@ -185,12 +185,14 @@ test "updates an existing user, if stale" do
local: false, local: false,
nickname: "admin@mastodon.example.org", nickname: "admin@mastodon.example.org",
ap_id: "http://mastodon.example.org/users/admin", ap_id: "http://mastodon.example.org/users/admin",
last_refreshed_at: a_week_ago last_refreshed_at: a_week_ago,
info: %{}
) )
assert orig_user.last_refreshed_at == a_week_ago assert orig_user.last_refreshed_at == a_week_ago
user = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin") user = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
assert user.info.source_data["endpoints"]
refute user.last_refreshed_at == orig_user.last_refreshed_at refute user.last_refreshed_at == orig_user.last_refreshed_at
end end
@ -311,45 +313,45 @@ test "it sets the info->note_count property" do
user = User.get_by_ap_id(note.data["actor"]) user = User.get_by_ap_id(note.data["actor"])
assert user.info["note_count"] == nil assert user.info.note_count == 0
{:ok, user} = User.update_note_count(user) {:ok, user} = User.update_note_count(user)
assert user.info["note_count"] == 1 assert user.info.note_count == 1
end end
test "it increases the info->note_count property" do test "it increases the info->note_count property" do
note = insert(:note) note = insert(:note)
user = User.get_by_ap_id(note.data["actor"]) user = User.get_by_ap_id(note.data["actor"])
assert user.info["note_count"] == nil assert user.info.note_count == 0
{:ok, user} = User.increase_note_count(user) {:ok, user} = User.increase_note_count(user)
assert user.info["note_count"] == 1 assert user.info.note_count == 1
{:ok, user} = User.increase_note_count(user) {:ok, user} = User.increase_note_count(user)
assert user.info["note_count"] == 2 assert user.info.note_count == 2
end end
test "it decreases the info->note_count property" do test "it decreases the info->note_count property" do
note = insert(:note) note = insert(:note)
user = User.get_by_ap_id(note.data["actor"]) user = User.get_by_ap_id(note.data["actor"])
assert user.info["note_count"] == nil assert user.info.note_count == 0
{:ok, user} = User.increase_note_count(user) {:ok, user} = User.increase_note_count(user)
assert user.info["note_count"] == 1 assert user.info.note_count == 1
{:ok, user} = User.decrease_note_count(user) {:ok, user} = User.decrease_note_count(user)
assert user.info["note_count"] == 0 assert user.info.note_count == 0
{:ok, user} = User.decrease_note_count(user) {:ok, user} = User.decrease_note_count(user)
assert user.info["note_count"] == 0 assert user.info.note_count == 0
end end
test "it sets the info->follower_count property" do test "it sets the info->follower_count property" do
@ -358,11 +360,11 @@ test "it sets the info->follower_count property" do
User.follow(follower, user) User.follow(follower, user)
assert user.info["follower_count"] == nil assert user.info.follower_count == 0
{:ok, user} = User.update_follower_count(user) {:ok, user} = User.update_follower_count(user)
assert user.info["follower_count"] == 1 assert user.info.follower_count == 1
end end
end end
@ -489,11 +491,11 @@ test "get recipients from activity" do
test ".deactivate can de-activate then re-activate a user" do test ".deactivate can de-activate then re-activate a user" do
user = insert(:user) user = insert(:user)
assert false == !!user.info["deactivated"] assert false == user.info.deactivated
{:ok, user} = User.deactivate(user) {:ok, user} = User.deactivate(user)
assert true == user.info["deactivated"] assert true == user.info.deactivated
{:ok, user} = User.deactivate(user, false) {:ok, user} = User.deactivate(user, false)
assert false == !!user.info["deactivated"] assert false == user.info.deactivated
end end
test ".delete deactivates a user, all follow relationships and all create activities" do test ".delete deactivates a user, all follow relationships and all create activities" do
@ -517,7 +519,7 @@ test ".delete deactivates a user, all follow relationships and all create activi
follower = Repo.get(User, follower.id) follower = Repo.get(User, follower.id)
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
assert user.info["deactivated"] assert user.info.deactivated
refute User.following?(user, followed) refute User.following?(user, followed)
refute User.following?(followed, follower) refute User.following?(followed, follower)
@ -546,7 +548,7 @@ test "html_filter_policy returns nil when rich-text is enabled" do
end end
test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
user = insert(:user, %{info: %{"no_rich_text" => true}}) user = insert(:user, %{info: %{no_rich_text: true}})
assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user) assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
end end

View File

@ -14,8 +14,8 @@ test "it returns a user" do
{:ok, user} = ActivityPub.make_user_from_ap_id(user_id) {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
assert user.ap_id == user_id assert user.ap_id == user_id
assert user.nickname == "admin@mastodon.example.org" assert user.nickname == "admin@mastodon.example.org"
assert user.info["source_data"] assert user.info.source_data
assert user.info["ap_enabled"] assert user.info.ap_enabled
assert user.follower_address == "http://mastodon.example.org/users/admin/followers" assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
end end
end end

View File

@ -92,7 +92,7 @@ test "it works for incoming notices" do
user = User.get_by_ap_id(object["actor"]) user = User.get_by_ap_id(object["actor"])
assert user.info["note_count"] == 1 assert user.info.note_count == 1
end end
test "it works for incoming notices with hashtags" do test "it works for incoming notices with hashtags" do
@ -307,7 +307,7 @@ test "it works for incoming update activities" do
} }
] ]
assert user.info["banner"]["url"] == [ assert user.info.banner["url"] == [
%{ %{
"href" => "href" =>
"https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
@ -337,7 +337,7 @@ test "it works for incoming update activities which lock the account" do
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data) {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
user = User.get_cached_by_ap_id(data["actor"]) user = User.get_cached_by_ap_id(data["actor"])
assert user.info["locked"] == true assert user.info.locked == true
end end
test "it works for incoming deletes" do test "it works for incoming deletes" do
@ -543,7 +543,7 @@ test "it works for incoming accepts which were pre-accepted" do
test "it works for incoming accepts which were orphaned" do test "it works for incoming accepts which were orphaned" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, %{info: %{"locked" => true}}) followed = insert(:user, %{info: %User.Info{locked: true}})
{:ok, follow_activity} = ActivityPub.follow(follower, followed) {:ok, follow_activity} = ActivityPub.follow(follower, followed)
@ -565,7 +565,7 @@ test "it works for incoming accepts which were orphaned" do
test "it works for incoming accepts which are referenced by IRI only" do test "it works for incoming accepts which are referenced by IRI only" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, %{info: %{"locked" => true}}) followed = insert(:user, %{info: %User.Info{locked: true}})
{:ok, follow_activity} = ActivityPub.follow(follower, followed) {:ok, follow_activity} = ActivityPub.follow(follower, followed)
@ -585,7 +585,7 @@ test "it works for incoming accepts which are referenced by IRI only" do
test "it fails for incoming accepts which cannot be correlated" do test "it fails for incoming accepts which cannot be correlated" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, %{info: %{"locked" => true}}) followed = insert(:user, %{info: %User.Info{locked: true}})
accept_data = accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json") File.read!("test/fixtures/mastodon-accept-activity.json")
@ -604,7 +604,7 @@ test "it fails for incoming accepts which cannot be correlated" do
test "it fails for incoming rejects which cannot be correlated" do test "it fails for incoming rejects which cannot be correlated" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, %{info: %{"locked" => true}}) followed = insert(:user, %{info: %User.Info{locked: true}})
accept_data = accept_data =
File.read!("test/fixtures/mastodon-reject-activity.json") File.read!("test/fixtures/mastodon-reject-activity.json")
@ -623,7 +623,7 @@ test "it fails for incoming rejects which cannot be correlated" do
test "it works for incoming rejects which are orphaned" do test "it works for incoming rejects which are orphaned" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, %{info: %{"locked" => true}}) followed = insert(:user, %{info: %User.Info{locked: true}})
{:ok, follower} = User.follow(follower, followed) {:ok, follower} = User.follow(follower, followed)
{:ok, _follow_activity} = ActivityPub.follow(follower, followed) {:ok, _follow_activity} = ActivityPub.follow(follower, followed)
@ -648,7 +648,7 @@ test "it works for incoming rejects which are orphaned" do
test "it works for incoming rejects which are referenced by IRI only" do test "it works for incoming rejects which are referenced by IRI only" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, %{info: %{"locked" => true}}) followed = insert(:user, %{info: %User.Info{locked: true}})
{:ok, follower} = User.follow(follower, followed) {:ok, follower} = User.follow(follower, followed)
{:ok, follow_activity} = ActivityPub.follow(follower, followed) {:ok, follow_activity} = ActivityPub.follow(follower, followed)
@ -815,18 +815,18 @@ test "it upgrades a user to activitypub" do
assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
assert user.info["note_count"] == 1 assert user.info.note_count == 1
{:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
assert user.info["ap_enabled"] assert user.info.ap_enabled
assert user.info["note_count"] == 1 assert user.info.note_count == 1
assert user.follower_address == "https://niu.moe/users/rye/followers" assert user.follower_address == "https://niu.moe/users/rye/followers"
# Wait for the background task # Wait for the background task
:timer.sleep(1000) :timer.sleep(1000)
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
assert user.info["note_count"] == 1 assert user.info.note_count == 1
activity = Repo.get(Activity, activity.id) activity = Repo.get(Activity, activity.id)
assert user.follower_address in activity.recipients assert user.follower_address in activity.recipients
@ -847,7 +847,7 @@ test "it upgrades a user to activitypub" do
"https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
} }
] ]
} = user.info["banner"] } = user.info.banner
refute "..." in activity.recipients refute "..." in activity.recipients

View File

@ -8,7 +8,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
describe "/api/pleroma/admin/user" do describe "/api/pleroma/admin/user" do
test "Delete" do test "Delete" do
admin = insert(:user, info: %{"is_admin" => true}) admin = insert(:user, info: %{is_admin: true})
user = insert(:user) user = insert(:user)
conn = conn =
@ -21,7 +21,7 @@ test "Delete" do
end end
test "Create" do test "Create" do
admin = insert(:user, info: %{"is_admin" => true}) admin = insert(:user, info: %{is_admin: true})
conn = conn =
build_conn() build_conn()
@ -39,7 +39,7 @@ test "Create" do
describe "/api/pleroma/admin/permission_group" do describe "/api/pleroma/admin/permission_group" do
test "GET is giving user_info" do test "GET is giving user_info" do
admin = insert(:user, info: %{"is_admin" => true}) admin = insert(:user, info: %{is_admin: true})
conn = conn =
build_conn() build_conn()
@ -47,33 +47,30 @@ test "GET is giving user_info" do
|> put_req_header("accept", "application/json") |> put_req_header("accept", "application/json")
|> get("/api/pleroma/admin/permission_group/#{admin.nickname}") |> get("/api/pleroma/admin/permission_group/#{admin.nickname}")
assert json_response(conn, 200) == admin.info assert json_response(conn, 200) == %{
"is_admin" => true,
"is_moderator" => false
}
end end
test "/:right POST, can add to a permission group" do test "/:right POST, can add to a permission group" do
admin = insert(:user, info: %{"is_admin" => true}) admin = insert(:user, info: %{is_admin: true})
user = insert(:user) user = insert(:user)
user_info =
user.info
|> Map.put("is_admin", true)
conn = conn =
build_conn() build_conn()
|> assign(:user, admin) |> assign(:user, admin)
|> put_req_header("accept", "application/json") |> put_req_header("accept", "application/json")
|> post("/api/pleroma/admin/permission_group/#{user.nickname}/admin") |> post("/api/pleroma/admin/permission_group/#{user.nickname}/admin")
assert json_response(conn, 200) == user_info assert json_response(conn, 200) == %{
"is_admin" => true
}
end end
test "/:right DELETE, can remove from a permission group" do test "/:right DELETE, can remove from a permission group" do
admin = insert(:user, info: %{"is_admin" => true}) admin = insert(:user, info: %{is_admin: true})
user = insert(:user, info: %{"is_admin" => true}) user = insert(:user, info: %{is_admin: true})
user_info =
user.info
|> Map.put("is_admin", false)
conn = conn =
build_conn() build_conn()
@ -81,12 +78,14 @@ test "/:right DELETE, can remove from a permission group" do
|> put_req_header("accept", "application/json") |> put_req_header("accept", "application/json")
|> delete("/api/pleroma/admin/permission_group/#{user.nickname}/admin") |> delete("/api/pleroma/admin/permission_group/#{user.nickname}/admin")
assert json_response(conn, 200) == user_info assert json_response(conn, 200) == %{
"is_admin" => false
}
end end
end end
test "/api/pleroma/admin/invite_token" do test "/api/pleroma/admin/invite_token" do
admin = insert(:user, info: %{"is_admin" => true}) admin = insert(:user, info: %{is_admin: true})
conn = conn =
build_conn() build_conn()
@ -98,8 +97,8 @@ test "/api/pleroma/admin/invite_token" do
end end
test "/api/pleroma/admin/password_reset" do test "/api/pleroma/admin/password_reset" do
admin = insert(:user, info: %{"is_admin" => true}) admin = insert(:user, info: %{is_admin: true})
user = insert(:user, info: %{"is_admin" => true}) user = insert(:user)
conn = conn =
build_conn() build_conn()

View File

@ -17,7 +17,7 @@ test "it adds emoji when updating profiles" do
CommonAPI.update(user) CommonAPI.update(user)
user = User.get_cached_by_ap_id(user.ap_id) user = User.get_cached_by_ap_id(user.ap_id)
[karjalanpiirakka] = user.info["source_data"]["tag"] [karjalanpiirakka] = user.info.source_data["tag"]
assert karjalanpiirakka["name"] == ":karjalanpiirakka:" assert karjalanpiirakka["name"] == ":karjalanpiirakka:"
end end

View File

@ -17,7 +17,7 @@ test "Represent a user account" do
user = user =
insert(:user, %{ insert(:user, %{
info: %{"note_count" => 5, "follower_count" => 3, "source_data" => source_data}, info: %{note_count: 5, follower_count: 3, source_data: source_data},
nickname: "shp@shitposter.club", nickname: "shp@shitposter.club",
name: ":karjalanpiirakka: shp", name: ":karjalanpiirakka: shp",
bio: "<script src=\"invalid-html\"></script><span>valid html</span>", bio: "<script src=\"invalid-html\"></script><span>valid html</span>",
@ -63,7 +63,7 @@ test "Represent a user account" do
test "Represent a Service(bot) account" do test "Represent a Service(bot) account" do
user = user =
insert(:user, %{ insert(:user, %{
info: %{"note_count" => 5, "follower_count" => 3, "source_data" => %{"type" => "Service"}}, info: %{note_count: 5, follower_count: 3, source_data: %{"type" => "Service"}},
nickname: "shp@shitposter.club", nickname: "shp@shitposter.club",
inserted_at: ~N[2017-08-15 15:47:06.597036] inserted_at: ~N[2017-08-15 15:47:06.597036]
}) })

View File

@ -252,7 +252,7 @@ test "verify_credentials", %{conn: conn} do
end end
test "verify_credentials default scope unlisted", %{conn: conn} do test "verify_credentials default scope unlisted", %{conn: conn} do
user = insert(:user, %{info: %{"default_scope" => "unlisted"}}) user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
conn = conn =
conn conn
@ -845,7 +845,7 @@ test "returns the relationships for the current user", %{conn: conn} do
describe "locked accounts" do describe "locked accounts" do
test "/api/v1/follow_requests works" do test "/api/v1/follow_requests works" do
user = insert(:user, %{info: %{"locked" => true}}) user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = ActivityPub.follow(other_user, user) {:ok, activity} = ActivityPub.follow(other_user, user)
@ -865,7 +865,7 @@ test "/api/v1/follow_requests works" do
end end
test "/api/v1/follow_requests/:id/authorize works" do test "/api/v1/follow_requests/:id/authorize works" do
user = insert(:user, %{info: %{"locked" => true}}) user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = ActivityPub.follow(other_user, user) {:ok, activity} = ActivityPub.follow(other_user, user)
@ -890,7 +890,7 @@ test "/api/v1/follow_requests/:id/authorize works" do
end end
test "verify_credentials", %{conn: conn} do test "verify_credentials", %{conn: conn} do
user = insert(:user, %{info: %{"default_scope" => "private"}}) user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
conn = conn =
conn conn
@ -902,7 +902,7 @@ test "verify_credentials", %{conn: conn} do
end end
test "/api/v1/follow_requests/:id/reject works" do test "/api/v1/follow_requests/:id/reject works" do
user = insert(:user, %{info: %{"locked" => true}}) user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = ActivityPub.follow(other_user, user) {:ok, activity} = ActivityPub.follow(other_user, user)
@ -1105,7 +1105,7 @@ test "blocking / unblocking a domain", %{conn: conn} do
refute User.blocks?(user, other_user) refute User.blocks?(user, other_user)
end end
test "getting a list of domain blocks" do test "getting a list of domain blocks", %{conn: conn} do
user = insert(:user) user = insert(:user)
{:ok, user} = User.block_domain(user, "bad.site") {:ok, user} = User.block_domain(user, "bad.site")
@ -1263,6 +1263,18 @@ test "updates the user's bio", %{conn: conn} do
assert user["note"] == "I drink #cofe" assert user["note"] == "I drink #cofe"
end end
test "updates the user's locking status", %{conn: conn} do
user = insert(:user)
conn =
conn
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
assert user = json_response(conn, 200)
assert user["locked"] == true
end
test "updates the user's name", %{conn: conn} do test "updates the user's name", %{conn: conn} do
user = insert(:user) user = insert(:user)
@ -1289,8 +1301,8 @@ test "updates the user's avatar", %{conn: conn} do
|> assign(:user, user) |> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar}) |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
assert user = json_response(conn, 200) assert user_response = json_response(conn, 200)
assert user["avatar"] != "https://placehold.it/48x48" assert user_response["avatar"] != User.avatar_url(user)
end end
test "updates the user's banner", %{conn: conn} do test "updates the user's banner", %{conn: conn} do
@ -1307,8 +1319,8 @@ test "updates the user's banner", %{conn: conn} do
|> assign(:user, user) |> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{"header" => new_header}) |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
assert user = json_response(conn, 200) assert user_response = json_response(conn, 200)
assert user["header"] != "https://placehold.it/700x335" assert user_response["header"] != User.banner_url(user)
end end
end end

View File

@ -4,7 +4,7 @@ defmodule Pleroma.Web.NodeInfoTest do
import Pleroma.Factory import Pleroma.Factory
test "nodeinfo shows staff accounts", %{conn: conn} do test "nodeinfo shows staff accounts", %{conn: conn} do
user = insert(:user, %{local: true, info: %{"is_moderator" => true}}) user = insert(:user, %{local: true, info: %{is_moderator: true}})
conn = conn =
conn conn
@ -15,7 +15,7 @@ test "nodeinfo shows staff accounts", %{conn: conn} do
assert user.ap_id in result["metadata"]["staffAccounts"] assert user.ap_id in result["metadata"]["staffAccounts"]
end end
test "returns 404 when federation is disabled" do test "returns 404 when federation is disabled", %{conn: conn} do
instance = instance =
Application.get_env(:pleroma, :instance) Application.get_env(:pleroma, :instance)
|> Keyword.put(:federating, false) |> Keyword.put(:federating, false)
@ -37,7 +37,7 @@ test "returns 404 when federation is disabled" do
Application.put_env(:pleroma, :instance, instance) Application.put_env(:pleroma, :instance, instance)
end end
test "returns 200 when federation is enabled" do test "returns 200 when federation is enabled", %{conn: conn} do
conn conn
|> get("/.well-known/nodeinfo") |> get("/.well-known/nodeinfo")
|> json_response(200) |> json_response(200)

View File

@ -31,14 +31,16 @@ test "decodes a salmon with a changed magic key", %{conn: conn} do
# Set a wrong magic-key for a user so it has to refetch # Set a wrong magic-key for a user so it has to refetch
salmon_user = User.get_by_ap_id("http://gs.example.org:4040/index.php/user/1") salmon_user = User.get_by_ap_id("http://gs.example.org:4040/index.php/user/1")
# Wrong key # Wrong key
info = info_cng =
salmon_user.info User.Info.remote_user_creation(salmon_user.info, %{
|> Map.put( magic_key:
"magic_key", "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB"
"RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" })
)
Repo.update(User.info_changeset(salmon_user, %{info: info})) cng =
Ecto.Changeset.change(salmon_user)
|> Ecto.Changeset.put_embed(:info, info_cng)
|> Repo.update()
conn = conn =
build_conn() build_conn()

View File

@ -17,7 +17,7 @@ test "handle incoming note - GS, Salmon" do
{:ok, [activity]} = OStatus.handle_incoming(incoming) {:ok, [activity]} = OStatus.handle_incoming(incoming)
user = User.get_by_ap_id(activity.data["actor"]) user = User.get_by_ap_id(activity.data["actor"])
assert user.info["note_count"] == 1 assert user.info.note_count == 1
assert activity.data["type"] == "Create" assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note" assert activity.data["object"]["type"] == "Note"
@ -319,7 +319,7 @@ test "tries to use the information in poco fields" do
assert user.name == "Constance Variable" assert user.name == "Constance Variable"
assert user.nickname == "lambadalambda@social.heldscal.la" assert user.nickname == "lambadalambda@social.heldscal.la"
assert user.local == false assert user.local == false
assert user.info["uri"] == uri assert user.info.uri == uri
assert user.ap_id == uri assert user.ap_id == uri
assert user.bio == "Call me Deacon Blues." assert user.bio == "Call me Deacon Blues."
assert user.avatar["type"] == "Image" assert user.avatar["type"] == "Image"
@ -329,6 +329,38 @@ test "tries to use the information in poco fields" do
assert user == user_again assert user == user_again
end end
test "find_or_make_user sets all the nessary input fields" do
uri = "https://social.heldscal.la/user/23211"
{:ok, user} = OStatus.find_or_make_user(uri)
assert user.info ==
%Pleroma.User.Info{
id: user.info.id,
ap_enabled: false,
background: nil,
banner: %{},
blocks: [],
deactivated: false,
default_scope: "public",
domain_blocks: [],
follower_count: 0,
is_admin: false,
is_moderator: false,
keys: nil,
locked: false,
no_rich_text: false,
note_count: 0,
settings: nil,
source_data: %{},
hub: "https://social.heldscal.la/main/push/hub",
magic_key:
"RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB",
salmon: "https://social.heldscal.la/main/salmon/user/23211",
topic: "https://social.heldscal.la/api/statuses/user_timeline/23211.atom",
uri: "https://social.heldscal.la/user/23211"
}
end
test "find_make_or_update_user takes an author element and returns an updated user" do test "find_make_or_update_user takes an author element and returns an updated user" do
uri = "https://social.heldscal.la/user/23211" uri = "https://social.heldscal.la/user/23211"
@ -447,7 +479,7 @@ test "it works for atom notes, too" do
end end
end end
test "it doesn't add nil in the do field" do test "it doesn't add nil in the to field" do
incoming = File.read!("test/fixtures/nil_mention_entry.xml") incoming = File.read!("test/fixtures/nil_mention_entry.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming) {:ok, [activity]} = OStatus.handle_incoming(incoming)

View File

@ -6,7 +6,7 @@ defmodule Pleroma.Web.OStatus.UserRepresenterTest do
alias Pleroma.User alias Pleroma.User
test "returns a user with id, uri, name and link" do test "returns a user with id, uri, name and link" do
user = build(:user, nickname: "レイン") user = insert(:user, %{nickname: "レイン"})
tuple = UserRepresenter.to_simple_form(user) tuple = UserRepresenter.to_simple_form(user)
res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> to_string res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> to_string

View File

@ -58,7 +58,7 @@ test "a like activity" do
end end
test "an activity" do test "an activity" do
{:ok, user} = UserBuilder.insert() user = insert(:user)
# {:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"}) # {:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"})
mentioned_user = insert(:user, %{nickname: "shp"}) mentioned_user = insert(:user, %{nickname: "shp"})

View File

@ -12,6 +12,36 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
import Pleroma.Factory import Pleroma.Factory
describe "POST /api/account/update_profile_banner" do
test "it updates the banner", %{conn: conn} do
user = insert(:user)
new_banner =
"data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
response =
conn
|> assign(:user, user)
|> post(authenticated_twitter_api__path(conn, :update_banner), %{"banner" => new_banner})
|> json_response(200)
end
end
describe "POST /api/qvitter/update_background_image" do
test "it updates the background", %{conn: conn} do
user = insert(:user)
new_bg =
"data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
response =
conn
|> assign(:user, user)
|> post(authenticated_twitter_api__path(conn, :update_background), %{"img" => new_bg})
|> json_response(200)
end
end
describe "POST /api/account/verify_credentials" do describe "POST /api/account/verify_credentials" do
setup [:valid_user] setup [:valid_user]
@ -31,26 +61,6 @@ test "with credentials", %{conn: conn, user: user} do
end end
end end
describe "POST /api/account/most_recent_notification" do
setup [:valid_user]
test "without valid credentials", %{conn: conn} do
conn = post(conn, "/api/account/most_recent_notification.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: user} do
conn =
conn
|> with_credentials(user.nickname, "test")
|> post("/api/account/most_recent_notification.json", %{id: "200"})
assert json_response(conn, 200)
user = User.get_by_nickname(user.nickname)
assert user.info["most_recent_notification"] == 200
end
end
describe "POST /statuses/update.json" do describe "POST /statuses/update.json" do
setup [:valid_user] setup [:valid_user]
@ -87,7 +97,7 @@ test "with credentials", %{conn: conn, user: user} do
describe "GET /statuses/public_timeline.json" do describe "GET /statuses/public_timeline.json" do
test "returns statuses", %{conn: conn} do test "returns statuses", %{conn: conn} do
{:ok, user} = UserBuilder.insert() user = insert(:user)
activities = ActivityBuilder.insert_list(30, %{}, %{user: user}) activities = ActivityBuilder.insert_list(30, %{}, %{user: user})
ActivityBuilder.insert_list(10, %{}, %{user: user}) ActivityBuilder.insert_list(10, %{}, %{user: user})
since_id = List.last(activities).id since_id = List.last(activities).id
@ -591,7 +601,7 @@ test "with credentials", %{conn: conn, user: current_user} do
|> post("/api/blocks/destroy.json", %{user_id: blocked.id}) |> post("/api/blocks/destroy.json", %{user_id: blocked.id})
current_user = Repo.get(User, current_user.id) current_user = Repo.get(User, current_user.id)
assert current_user.info["blocks"] == [] assert current_user.info.blocks == []
assert json_response(conn, 200) == assert json_response(conn, 200) ==
UserView.render("show.json", %{user: blocked, for: current_user}) UserView.render("show.json", %{user: blocked, for: current_user})
@ -966,7 +976,7 @@ test "it locks an account", %{conn: conn} do
}) })
user = Repo.get!(User, user.id) user = Repo.get!(User, user.id)
assert user.info["locked"] == true assert user.info.locked == true
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
end end
@ -982,7 +992,7 @@ test "it unlocks an account", %{conn: conn} do
}) })
user = Repo.get!(User, user.id) user = Repo.get!(User, user.id)
assert user.info["locked"] == false assert user.info.locked == false
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
end end
@ -1153,10 +1163,10 @@ test "with credentials and valid password", %{conn: conn, user: current_user} do
describe "GET /api/pleroma/friend_requests" do describe "GET /api/pleroma/friend_requests" do
test "it lists friend requests" do test "it lists friend requests" do
user = insert(:user, %{info: %{"locked" => true}}) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = ActivityPub.follow(other_user, user) {:ok, _activity} = ActivityPub.follow(other_user, user)
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)
@ -1175,10 +1185,10 @@ test "it lists friend requests" do
describe "POST /api/pleroma/friendships/approve" do describe "POST /api/pleroma/friendships/approve" do
test "it approves a friend request" do test "it approves a friend request" do
user = insert(:user, %{info: %{"locked" => true}}) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = ActivityPub.follow(other_user, user) {:ok, _activity} = ActivityPub.follow(other_user, user)
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)
@ -1198,10 +1208,10 @@ test "it approves a friend request" do
describe "POST /api/pleroma/friendships/deny" do describe "POST /api/pleroma/friendships/deny" do
test "it denies a friend request" do test "it denies a friend request" do
user = insert(:user, %{info: %{"locked" => true}}) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = ActivityPub.follow(other_user, user) {:ok, _activity} = ActivityPub.follow(other_user, user)
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)

View File

@ -10,7 +10,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
test "create a status" do test "create a status" do
user = insert(:user) user = insert(:user)
_mentioned_user = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"}) _mentioned_user = insert(:user, %{nickname: "shp", ap_id: "shp"})
object_data = %{ object_data = %{
"type" => "Image", "type" => "Image",
@ -67,7 +67,7 @@ test "create a status" do
user = User.get_by_ap_id(user.ap_id) user = User.get_by_ap_id(user.ap_id)
assert user.info["note_count"] == 1 assert user.info.note_count == 1
end end
test "create a status that is a reply" do test "create a status that is a reply" do
@ -116,7 +116,7 @@ test "Follow another user using screen_name" do
assert User.ap_followers(followed) in user.following assert User.ap_followers(followed) in user.following
followed = User.get_by_ap_id(followed.ap_id) followed = User.get_by_ap_id(followed.ap_id)
assert followed.info["follower_count"] == 1 assert followed.info.follower_count == 1
{:error, msg} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname}) {:error, msg} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
assert msg == "Could not follow user: #{followed.nickname} is already on your list." assert msg == "Could not follow user: #{followed.nickname} is already on your list."
@ -169,7 +169,7 @@ test "Unblock another user using user_id" do
{:ok, user, _unblocked} = TwitterAPI.block(user, %{"user_id" => unblocked.id}) {:ok, user, _unblocked} = TwitterAPI.block(user, %{"user_id" => unblocked.id})
{:ok, user, _unblocked} = TwitterAPI.unblock(user, %{"user_id" => unblocked.id}) {:ok, user, _unblocked} = TwitterAPI.unblock(user, %{"user_id" => unblocked.id})
assert user.info["blocks"] == [] assert user.info.blocks == []
end end
test "Unblock another user using screen_name" do test "Unblock another user using screen_name" do
@ -178,7 +178,7 @@ test "Unblock another user using screen_name" do
{:ok, user, _unblocked} = TwitterAPI.block(user, %{"screen_name" => unblocked.nickname}) {:ok, user, _unblocked} = TwitterAPI.block(user, %{"screen_name" => unblocked.nickname})
{:ok, user, _unblocked} = TwitterAPI.unblock(user, %{"screen_name" => unblocked.nickname}) {:ok, user, _unblocked} = TwitterAPI.unblock(user, %{"screen_name" => unblocked.nickname})
assert user.info["blocks"] == [] assert user.info.blocks == []
end end
test "upload a file" do test "upload a file" do

View File

@ -31,10 +31,10 @@ test "A user with emoji in username", %{user: user} do
expected = expected =
"<img height=\"32px\" width=\"32px\" alt=\"karjalanpiirakka\" title=\"karjalanpiirakka\" src=\"/file.png\" /> man" "<img height=\"32px\" width=\"32px\" alt=\"karjalanpiirakka\" title=\"karjalanpiirakka\" src=\"/file.png\" /> man"
user = %{ user =
user insert(:user, %{
| info: %{ info: %{
"source_data" => %{ source_data: %{
"tag" => [ "tag" => [
%{ %{
"type" => "Emoji", "type" => "Emoji",
@ -43,10 +43,10 @@ test "A user with emoji in username", %{user: user} do
} }
] ]
} }
} },
} name: ":karjalanpiirakka: man"
})
user = %{user | name: ":karjalanpiirakka: man"}
represented = UserView.render("show.json", %{user: user}) represented = UserView.render("show.json", %{user: user})
assert represented["name_html"] == expected assert represented["name_html"] == expected
end end
@ -103,7 +103,7 @@ test "A user" do
end end
test "A user for a given other follower", %{user: user} do test "A user for a given other follower", %{user: user} do
{:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]}) follower = insert(:user, %{following: [User.ap_followers(user)]})
{:ok, user} = User.update_follower_count(user) {:ok, user} = User.update_follower_count(user)
image = "http://localhost:4001/images/avi.png" image = "http://localhost:4001/images/avi.png"
banner = "http://localhost:4001/images/banner.png" banner = "http://localhost:4001/images/banner.png"
@ -186,7 +186,7 @@ test "A user that follows you", %{user: user} do
end end
test "a user that is a moderator" do test "a user that is a moderator" do
user = insert(:user, %{info: %{"is_moderator" => true}}) user = insert(:user, %{info: %{is_moderator: true}})
represented = UserView.render("show.json", %{user: user, for: user}) represented = UserView.render("show.json", %{user: user, for: user})
assert represented["rights"]["delete_others_notice"] assert represented["rights"]["delete_others_notice"]
@ -250,7 +250,7 @@ test "a user with mastodon fields" do
user = user =
insert(:user, %{ insert(:user, %{
info: %{ info: %{
"source_data" => %{ source_data: %{
"attachment" => "attachment" =>
Enum.map(fields, fn field -> Map.put(field, "type", "PropertyValue") end) Enum.map(fields, fn field -> Map.put(field, "type", "PropertyValue") end)
} }

View File

@ -99,15 +99,15 @@ test "it gets the xrd endpoint for statusnet" do
describe "ensure_keys_present" do describe "ensure_keys_present" do
test "it creates keys for a user and stores them in info" do test "it creates keys for a user and stores them in info" do
user = insert(:user) user = insert(:user)
refute is_binary(user.info["keys"]) refute is_binary(user.info.keys)
{:ok, user} = WebFinger.ensure_keys_present(user) {:ok, user} = WebFinger.ensure_keys_present(user)
assert is_binary(user.info["keys"]) assert is_binary(user.info.keys)
end end
test "it doesn't create keys if there already are some" do test "it doesn't create keys if there already are some" do
user = insert(:user, %{info: %{"keys" => "xxx"}}) user = insert(:user, %{info: %{keys: "xxx"}})
{:ok, user} = WebFinger.ensure_keys_present(user) {:ok, user} = WebFinger.ensure_keys_present(user)
assert user.info["keys"] == "xxx" assert user.info.keys == "xxx"
end end
end end
end end

View File

@ -99,7 +99,7 @@ def accepting_verifier(subscription) do
test "initiate a subscription for a given user and topic" do test "initiate a subscription for a given user and topic" do
subscriber = insert(:user) subscriber = insert(:user)
user = insert(:user, %{info: %{"topic" => "some_topic", "hub" => "some_hub"}}) user = insert(:user, %{info: %Pleroma.User.Info{topic: "some_topic", hub: "some_hub"}})
{:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1) {:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1)
assert websub.subscribers == [subscriber.ap_id] assert websub.subscribers == [subscriber.ap_id]