Merge remote-tracking branch 'remotes/origin/develop' into automatic-authentication-and-instance-publicity-checks

# Conflicts:
#	lib/pleroma/web/mastodon_api/controllers/account_controller.ex
This commit is contained in:
Ivan Tashkinov 2020-04-22 18:51:59 +03:00
commit 0062116e07
28 changed files with 225 additions and 102 deletions

View file

@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed ### Fixed
- Support pagination in conversations API - Support pagination in conversations API
- **Breaking**: SimplePolicy `:reject` and `:accept` allow deletions again - **Breaking**: SimplePolicy `:reject` and `:accept` allow deletions again
- Fix follower/blocks import when nicknames starts with @
## [unreleased-patch] ## [unreleased-patch]
### Fixed ### Fixed

View file

@ -7,13 +7,9 @@ This guide will assume you are on Debian Stretch. This guide should also work wi
* `postgresql` (9.6+, Ubuntu 16.04 comes with 9.5, you can get a newer version from [here](https://www.postgresql.org/download/linux/ubuntu/)) * `postgresql` (9.6+, Ubuntu 16.04 comes with 9.5, you can get a newer version from [here](https://www.postgresql.org/download/linux/ubuntu/))
* `postgresql-contrib` (9.6+, same situtation as above) * `postgresql-contrib` (9.6+, same situtation as above)
* `elixir` (1.5+, [install from here, Debian and Ubuntu ship older versions](https://elixir-lang.org/install.html#unix-and-unix-like) or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user) * `elixir` (1.8+, Follow the guide to install from the Erlang Solutions repo or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user)
* `erlang-dev` * `erlang-dev`
* `erlang-tools` * `erlang-nox`
* `erlang-parsetools`
* `erlang-eldap`, if you want to enable ldap authenticator
* `erlang-ssh`
* `erlang-xmerl`
* `git` * `git`
* `build-essential` * `build-essential`
@ -50,7 +46,7 @@ sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb
```shell ```shell
sudo apt update sudo apt update
sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh sudo apt install elixir erlang-dev erlang-nox
``` ```
### Install PleromaBE ### Install PleromaBE

View file

@ -10,21 +10,17 @@
### 必要なソフトウェア ### 必要なソフトウェア
- PostgreSQL 9.6以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください) - PostgreSQL 9.6以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください)
- postgresql-contrib 9.6以上 (同上) - `postgresql-contrib` 9.6以上 (同上)
- Elixir 1.5 以上 ([Debianのリポジトリからインストールしないこと ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください) - Elixir 1.8 以上 ([Debianのリポジトリからインストールしないこと ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください)
- erlang-dev - `erlang-dev`
- erlang-tools - `erlang-nox`
- erlang-parsetools - `git`
- erlang-eldap (LDAP認証を有効化するときのみ必要) - `build-essential`
- erlang-ssh
- erlang-xmerl
- git
- build-essential
#### このガイドで利用している追加パッケージ #### このガイドで利用している追加パッケージ
- nginx (おすすめです。他のリバースプロキシを使う場合は、参考となる設定をこのリポジトリから探してください) - `nginx` (おすすめです。他のリバースプロキシを使う場合は、参考となる設定をこのリポジトリから探してください)
- certbot (または何らかのLet's Encrypt向けACMEクライアント) - `certbot` (または何らかのLet's Encrypt向けACMEクライアント)
### システムを準備する ### システムを準備する
@ -51,7 +47,7 @@ sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb
* ElixirとErlangをインストールします、 * ElixirとErlangをインストールします、
``` ```
sudo apt update sudo apt update
sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh sudo apt install elixir erlang-dev erlang-nox
``` ```
### Pleroma BE (バックエンド) をインストールします ### Pleroma BE (バックエンド) をインストールします

View file

@ -47,7 +47,7 @@ defp filter(configs) do
@spec filter_group(atom(), keyword()) :: keyword() @spec filter_group(atom(), keyword()) :: keyword()
def filter_group(group, configs) do def filter_group(group, configs) do
Enum.reject(configs[group], fn {key, _v} -> Enum.reject(configs[group], fn {key, _v} ->
key in @reject_keys or (group == :phoenix and key == :serve_endpoints) key in @reject_keys or (group == :phoenix and key == :serve_endpoints) or group == :postgrex
end) end)
end end
end end

View file

@ -46,14 +46,6 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do
# We need to restart applications for loaded settings take effect # We need to restart applications for loaded settings take effect
# TODO: some problem with prometheus after restart!
reject_restart =
if restart_pleroma? do
[nil, :prometheus]
else
[:pleroma, nil, :prometheus]
end
{logger, other} = {logger, other} =
(Repo.all(ConfigDB) ++ deleted_settings) (Repo.all(ConfigDB) ++ deleted_settings)
|> Enum.map(&transform_and_merge/1) |> Enum.map(&transform_and_merge/1)
@ -65,10 +57,20 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
started_applications = Application.started_applications() started_applications = Application.started_applications()
# TODO: some problem with prometheus after restart!
reject = [nil, :prometheus, :postgrex]
reject =
if restart_pleroma? do
reject
else
[:pleroma | reject]
end
other other
|> Enum.map(&update/1) |> Enum.map(&update/1)
|> Enum.uniq() |> Enum.uniq()
|> Enum.reject(&(&1 in reject_restart)) |> Enum.reject(&(&1 in reject))
|> maybe_set_pleroma_last() |> maybe_set_pleroma_last()
|> Enum.each(&restart(started_applications, &1, Config.get(:env))) |> Enum.each(&restart(started_applications, &1, Config.get(:env)))

View file

@ -261,7 +261,7 @@ def decrease_replies_count(ap_id) do
end end
end end
def increase_vote_count(ap_id, name) do def increase_vote_count(ap_id, name, actor) do
with %Object{} = object <- Object.normalize(ap_id), with %Object{} = object <- Object.normalize(ap_id),
"Question" <- object.data["type"] do "Question" <- object.data["type"] do
multiple = Map.has_key?(object.data, "anyOf") multiple = Map.has_key?(object.data, "anyOf")
@ -276,12 +276,15 @@ def increase_vote_count(ap_id, name) do
option option
end) end)
voters = [actor | object.data["voters"] || []] |> Enum.uniq()
data = data =
if multiple do if multiple do
Map.put(object.data, "anyOf", options) Map.put(object.data, "anyOf", options)
else else
Map.put(object.data, "oneOf", options) Map.put(object.data, "oneOf", options)
end end
|> Map.put("voters", voters)
object object
|> Object.change(%{data: data}) |> Object.change(%{data: data})

View file

@ -1180,7 +1180,9 @@ def get_users_from_set(ap_ids, local_only \\ true) do
end end
@spec get_recipients_from_activity(Activity.t()) :: [User.t()] @spec get_recipients_from_activity(Activity.t()) :: [User.t()]
def get_recipients_from_activity(%Activity{recipients: to}) do def get_recipients_from_activity(%Activity{recipients: to, actor: actor}) do
to = [actor | to]
User.Query.build(%{recipients_from_activity: to, local: true, deactivated: false}) User.Query.build(%{recipients_from_activity: to, local: true, deactivated: false})
|> Repo.all() |> Repo.all()
end end

View file

@ -118,9 +118,10 @@ def decrease_replies_count_if_reply(_object), do: :noop
def increase_poll_votes_if_vote(%{ def increase_poll_votes_if_vote(%{
"object" => %{"inReplyTo" => reply_ap_id, "name" => name}, "object" => %{"inReplyTo" => reply_ap_id, "name" => name},
"type" => "Create" "type" => "Create",
"actor" => actor
}) do }) do
Object.increase_vote_count(reply_ap_id, name) Object.increase_vote_count(reply_ap_id, name, actor)
end end
def increase_poll_votes_if_vote(_create_data), do: :noop def increase_poll_votes_if_vote(_create_data), do: :noop

View file

@ -72,19 +72,24 @@ def perform(:incoming_ap_doc, params) do
# actor shouldn't be acting on objects outside their own AP server. # actor shouldn't be acting on objects outside their own AP server.
with {:ok, _user} <- ap_enabled_actor(params["actor"]), with {:ok, _user} <- ap_enabled_actor(params["actor"]),
nil <- Activity.normalize(params["id"]), nil <- Activity.normalize(params["id"]),
:ok <- Containment.contain_origin_from_id(params["actor"], params), {_, :ok} <-
{:correct_origin?, Containment.contain_origin_from_id(params["actor"], params)},
{:ok, activity} <- Transmogrifier.handle_incoming(params) do {:ok, activity} <- Transmogrifier.handle_incoming(params) do
{:ok, activity} {:ok, activity}
else else
{:correct_origin?, _} ->
Logger.debug("Origin containment failure for #{params["id"]}")
{:error, :origin_containment_failed}
%Activity{} -> %Activity{} ->
Logger.debug("Already had #{params["id"]}") Logger.debug("Already had #{params["id"]}")
:error {:error, :already_present}
_e -> e ->
# Just drop those for now # Just drop those for now
Logger.debug("Unhandled activity") Logger.debug("Unhandled activity")
Logger.debug(Jason.encode!(params, pretty: true)) Logger.debug(Jason.encode!(params, pretty: true))
:error {:error, e}
end end
end end

View file

@ -299,7 +299,7 @@ def lists(%{assigns: %{user: user, account: account}} = conn, _params) do
@doc "POST /api/v1/accounts/:id/follow" @doc "POST /api/v1/accounts/:id/follow"
def follow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do def follow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
{:error, :not_found} {:error, "Can not follow yourself"}
end end
def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
@ -312,7 +312,7 @@ def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
@doc "POST /api/v1/accounts/:id/unfollow" @doc "POST /api/v1/accounts/:id/unfollow"
def unfollow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do def unfollow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
{:error, :not_found} {:error, "Can not unfollow yourself"}
end end
def unfollow(%{assigns: %{user: follower, account: followed}} = conn, _params) do def unfollow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
@ -362,14 +362,15 @@ def unblock(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
end end
@doc "POST /api/v1/follows" @doc "POST /api/v1/follows"
def follow_by_uri(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do def follow_by_uri(conn, %{"uri" => uri}) do
with {_, %User{} = followed} <- {:followed, User.get_cached_by_nickname(uri)}, case User.get_cached_by_nickname(uri) do
{_, true} <- {:followed, follower.id != followed.id}, %User{} = user ->
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do conn
render(conn, "show.json", user: followed, for: follower) |> assign(:account, user)
else |> follow(%{})
{:followed, _} -> {:error, :not_found}
{:error, message} -> json_response(conn, :forbidden, %{error: message}) nil ->
{:error, :not_found}
end end
end end

View file

@ -19,6 +19,7 @@ def render("show.json", %{object: object, multiple: multiple, options: options}
expired: expired, expired: expired,
multiple: multiple, multiple: multiple,
votes_count: votes_count, votes_count: votes_count,
voters_count: (multiple || nil) && voters_count(object),
options: options, options: options,
voted: voted?(params), voted: voted?(params),
emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"]) emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
@ -62,6 +63,12 @@ defp options_and_votes_count(options) do
end) end)
end end
defp voters_count(%{data: %{"voters" => [_ | _] = voters}}) do
length(voters)
end
defp voters_count(_), do: 0
defp voted?(%{object: object} = opts) do defp voted?(%{object: object} = opts) do
if opts[:for] do if opts[:for] do
existing_votes = Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object) existing_votes = Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object)

View file

@ -55,11 +55,12 @@ def perform(
|> Jason.encode!() |> Jason.encode!()
|> push_message(build_sub(subscription), gcm_api_key, subscription) |> push_message(build_sub(subscription), gcm_api_key, subscription)
end end
|> (&{:ok, &1}).()
end end
def perform(_) do def perform(_) do
Logger.warn("Unknown notification type") Logger.warn("Unknown notification type")
:error {:error, :unknown_type}
end end
@doc "Push message to web" @doc "Push message to web"

View file

@ -158,24 +158,6 @@ defp should_send?(%User{} = user, %Notification{activity: activity}) do
should_send?(user, activity) should_send?(user, activity)
end end
def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do
Enum.each(topics[topic] || [], fn %StreamerSocket{
transport_pid: transport_pid,
user: socket_user
} ->
# Get the current user so we have up-to-date blocks etc.
if socket_user do
user = User.get_cached_by_ap_id(socket_user.ap_id)
if should_send?(user, item) do
send(transport_pid, {:text, StreamerView.render("update.json", item, user)})
end
else
send(transport_pid, {:text, StreamerView.render("update.json", item)})
end
end)
end
def push_to_socket(topics, topic, %Participation{} = participation) do def push_to_socket(topics, topic, %Participation{} = participation) do
Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} -> Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} ->
send(transport_pid, {:text, StreamerView.render("conversation.json", participation)}) send(transport_pid, {:text, StreamerView.render("conversation.json", participation)})

View file

@ -1,8 +1,8 @@
<%= case @mediaType do %> <%= case @mediaType do %>
<% "audio" -> %> <% "audio" -> %>
<audio src="<%= @url %>" controls="controls"></audio> <audio class="u-audio" src="<%= @url %>" controls="controls"></audio>
<% "video" -> %> <% "video" -> %>
<video src="<%= @url %>" controls="controls"></video> <video class="u-video" src="<%= @url %>" controls="controls"></video>
<% _ -> %> <% _ -> %>
<img src="<%= @url %>" alt="<%= @name %>" title="<%= @name %>"> <img class="u-photo" src="<%= @url %>" alt="<%= @name %>" title="<%= @name %>">
<% end %> <% end %>

View file

@ -1,12 +1,16 @@
<div class="activity" <%= if @selected do %> id="selected" <% end %>> <div class="activity h-entry" <%= if @selected do %> id="selected" <% end %>>
<p class="pull-right"> <p class="pull-right">
<%= link format_date(@published), to: @link, class: "activity-link" %> <a class="activity-link u-url u-uid" href="<%= @link %>">
<time class="dt-published" datetime="<%= @published %>">
<%= format_date(@published) %>
</time>
</a>
</p> </p>
<%= render("_user_card.html", %{user: @user}) %> <%= render("_user_card.html", %{user: @user}) %>
<div class="activity-content"> <div class="activity-content">
<%= if @title != "" do %> <%= if @title != "" do %>
<details <%= if open_content?() do %>open<% end %>> <details <%= if open_content?() do %>open<% end %>>
<summary><%= raw @title %></summary> <summary class="p-name"><%= raw @title %></summary>
<div class="e-content"><%= raw @content %></div> <div class="e-content"><%= raw @content %></div>
</details> </details>
<% else %> <% else %>

View file

@ -1,10 +1,10 @@
<div class="p-author h-card"> <div class="p-author h-card">
<a class="u-url" rel="author noopener" href="<%= (@user.uri || @user.ap_id) %>"> <a class="u-url" rel="author noopener" href="<%= (@user.uri || @user.ap_id) %>">
<div class="avatar"> <div class="avatar">
<img src="<%= User.avatar_url(@user) |> MediaProxy.url %>" width="48" height="48" alt=""> <img class="u-photo" src="<%= User.avatar_url(@user) |> MediaProxy.url %>" width="48" height="48" alt="">
</div> </div>
<span class="display-name"> <span class="display-name">
<bdi><%= raw Formatter.emojify(@user.name, @user.emoji) %></bdi> <bdi class="p-name"><%= raw Formatter.emojify(@user.name, @user.emoji) %></bdi>
<span class="nickname"><%= @user.nickname %></span> <span class="nickname"><%= @user.nickname %></span>
</span> </span>
</a> </a>

View file

@ -192,27 +192,27 @@ def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
end end
def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
with lines <- String.split(list, "\n"), followed_identifiers =
followed_identifiers <- list
Enum.map(lines, fn line -> |> String.split("\n")
String.split(line, ",") |> List.first() |> Enum.map(&(&1 |> String.split(",") |> List.first()))
end) |> List.delete("Account address")
|> List.delete("Account address") do |> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@")))
|> Enum.reject(&(&1 == ""))
User.follow_import(follower, followed_identifiers) User.follow_import(follower, followed_identifiers)
json(conn, "job started") json(conn, "job started")
end end
end
def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
blocks_import(conn, %{"list" => File.read!(listfile.path)}) blocks_import(conn, %{"list" => File.read!(listfile.path)})
end end
def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
with blocked_identifiers <- String.split(list) do blocked_identifiers = list |> String.split() |> Enum.map(&String.trim_leading(&1, "@"))
User.blocks_import(blocker, blocked_identifiers) User.blocks_import(blocker, blocked_identifiers)
json(conn, "job started") json(conn, "job started")
end end
end
def change_password(%{assigns: %{user: user}} = conn, params) do def change_password(%{assigns: %{user: user}} = conn, params) do
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do case CommonAPI.Utils.confirm_current_password(user, params["password"]) do

View file

@ -35,7 +35,7 @@ def perform(
_job _job
) do ) do
blocker = User.get_cached_by_id(blocker_id) blocker = User.get_cached_by_id(blocker_id)
User.perform(:blocks_import, blocker, blocked_identifiers) {:ok, User.perform(:blocks_import, blocker, blocked_identifiers)}
end end
def perform( def perform(
@ -47,7 +47,7 @@ def perform(
_job _job
) do ) do
follower = User.get_cached_by_id(follower_id) follower = User.get_cached_by_id(follower_id)
User.perform(:follow_import, follower, followed_identifiers) {:ok, User.perform(:follow_import, follower, followed_identifiers)}
end end
def perform(%{"op" => "media_proxy_preload", "message" => message}, _job) do def perform(%{"op" => "media_proxy_preload", "message" => message}, _job) do

View file

@ -16,6 +16,7 @@ test "transfer config values from db to env" do
refute Application.get_env(:pleroma, :test_key) refute Application.get_env(:pleroma, :test_key)
refute Application.get_env(:idna, :test_key) refute Application.get_env(:idna, :test_key)
refute Application.get_env(:quack, :test_key) refute Application.get_env(:quack, :test_key)
refute Application.get_env(:postgrex, :test_key)
initial = Application.get_env(:logger, :level) initial = Application.get_env(:logger, :level)
ConfigDB.create(%{ ConfigDB.create(%{
@ -36,6 +37,12 @@ test "transfer config values from db to env" do
value: [:test_value1, :test_value2] value: [:test_value1, :test_value2]
}) })
ConfigDB.create(%{
group: ":postgrex",
key: ":test_key",
value: :value
})
ConfigDB.create(%{group: ":logger", key: ":level", value: :debug}) ConfigDB.create(%{group: ":logger", key: ":level", value: :debug})
TransferTask.start_link([]) TransferTask.start_link([])
@ -44,11 +51,13 @@ test "transfer config values from db to env" do
assert Application.get_env(:idna, :test_key) == [live: 15, com: 35] assert Application.get_env(:idna, :test_key) == [live: 15, com: 35]
assert Application.get_env(:quack, :test_key) == [:test_value1, :test_value2] assert Application.get_env(:quack, :test_key) == [:test_value1, :test_value2]
assert Application.get_env(:logger, :level) == :debug assert Application.get_env(:logger, :level) == :debug
assert Application.get_env(:postgrex, :test_key) == :value
on_exit(fn -> on_exit(fn ->
Application.delete_env(:pleroma, :test_key) Application.delete_env(:pleroma, :test_key)
Application.delete_env(:idna, :test_key) Application.delete_env(:idna, :test_key)
Application.delete_env(:quack, :test_key) Application.delete_env(:quack, :test_key)
Application.delete_env(:postgrex, :test_key)
Application.put_env(:logger, :level, initial) Application.put_env(:logger, :level, initial)
end) end)
end end

View file

@ -7,3 +7,5 @@
config :quack, level: :info config :quack, level: :info
config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox
config :postgrex, :json_library, Poison

View file

@ -38,7 +38,7 @@ test "error if file with custom settings doesn't exist" do
on_exit(fn -> Application.put_env(:quack, :level, initial) end) on_exit(fn -> Application.put_env(:quack, :level, initial) end)
end end
test "settings are migrated to db" do test "filtered settings are migrated to db" do
assert Repo.all(ConfigDB) == [] assert Repo.all(ConfigDB) == []
Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
@ -47,6 +47,7 @@ test "settings are migrated to db" do
config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"})
config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"}) config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"})
refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"})
refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"})
assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]] assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]]
assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]] assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]]

View file

@ -756,8 +756,8 @@ test "it imports user followings from list" do
] ]
{:ok, job} = User.follow_import(user1, identifiers) {:ok, job} = User.follow_import(user1, identifiers)
result = ObanHelpers.perform(job)
assert {:ok, result} = ObanHelpers.perform(job)
assert is_list(result) assert is_list(result)
assert result == [user2, user3] assert result == [user2, user3]
end end
@ -979,14 +979,26 @@ test "it imports user blocks from list" do
] ]
{:ok, job} = User.blocks_import(user1, identifiers) {:ok, job} = User.blocks_import(user1, identifiers)
result = ObanHelpers.perform(job)
assert {:ok, result} = ObanHelpers.perform(job)
assert is_list(result) assert is_list(result)
assert result == [user2, user3] assert result == [user2, user3]
end end
end end
describe "get_recipients_from_activity" do describe "get_recipients_from_activity" do
test "works for announces" do
actor = insert(:user)
user = insert(:user, local: true)
{:ok, activity} = CommonAPI.post(actor, %{"status" => "hello"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user)
recipients = User.get_recipients_from_activity(announce)
assert user in recipients
end
test "get recipients" do test "get recipients" do
actor = insert(:user) actor = insert(:user)
user = insert(:user, local: true) user = insert(:user, local: true)

View file

@ -130,6 +130,9 @@ test "successfully processes incoming AP docs with correct origin" do
assert {:ok, job} = Federator.incoming_ap_doc(params) assert {:ok, job} = Federator.incoming_ap_doc(params)
assert {:ok, _activity} = ObanHelpers.perform(job) assert {:ok, _activity} = ObanHelpers.perform(job)
assert {:ok, job} = Federator.incoming_ap_doc(params)
assert {:error, :already_present} = ObanHelpers.perform(job)
end end
test "rejects incoming AP docs with incorrect origin" do test "rejects incoming AP docs with incorrect origin" do
@ -148,7 +151,7 @@ test "rejects incoming AP docs with incorrect origin" do
} }
assert {:ok, job} = Federator.incoming_ap_doc(params) assert {:ok, job} = Federator.incoming_ap_doc(params)
assert :error = ObanHelpers.perform(job) assert {:error, :origin_containment_failed} = ObanHelpers.perform(job)
end end
test "it does not crash if MRF rejects the post" do test "it does not crash if MRF rejects the post" do
@ -164,7 +167,7 @@ test "it does not crash if MRF rejects the post" do
|> Poison.decode!() |> Poison.decode!()
assert {:ok, job} = Federator.incoming_ap_doc(params) assert {:ok, job} = Federator.incoming_ap_doc(params)
assert :error = ObanHelpers.perform(job) assert {:error, _} = ObanHelpers.perform(job)
end end
end end
end end

View file

@ -681,17 +681,17 @@ test "following without reblogs" do
test "following / unfollowing errors", %{user: user, conn: conn} do test "following / unfollowing errors", %{user: user, conn: conn} do
# self follow # self follow
conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow") conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
assert %{"error" => "Record not found"} = json_response(conn_res, 404) assert %{"error" => "Can not follow yourself"} = json_response(conn_res, 400)
# self unfollow # self unfollow
user = User.get_cached_by_id(user.id) user = User.get_cached_by_id(user.id)
conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow") conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
assert %{"error" => "Record not found"} = json_response(conn_res, 404) assert %{"error" => "Can not unfollow yourself"} = json_response(conn_res, 400)
# self follow via uri # self follow via uri
user = User.get_cached_by_id(user.id) user = User.get_cached_by_id(user.id)
conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname}) conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
assert %{"error" => "Record not found"} = json_response(conn_res, 404) assert %{"error" => "Can not follow yourself"} = json_response(conn_res, 400)
# follow non existing user # follow non existing user
conn_res = post(conn, "/api/v1/accounts/doesntexist/follow") conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")

View file

@ -43,7 +43,8 @@ test "renders a poll" do
%{title: "why are you even asking?", votes_count: 0} %{title: "why are you even asking?", votes_count: 0}
], ],
voted: false, voted: false,
votes_count: 0 votes_count: 0,
voters_count: nil
} }
result = PollView.render("show.json", %{object: object}) result = PollView.render("show.json", %{object: object})
@ -69,9 +70,20 @@ test "detects if it is multiple choice" do
} }
}) })
voter = insert(:user)
object = Object.normalize(activity) object = Object.normalize(activity)
assert %{multiple: true} = PollView.render("show.json", %{object: object}) {:ok, _votes, object} = CommonAPI.vote(voter, object, [0, 1])
assert match?(
%{
multiple: true,
voters_count: 1,
votes_count: 2
},
PollView.render("show.json", %{object: object})
)
end end
test "detects emoji" do test "detects emoji" do

View file

@ -63,12 +63,12 @@ test "performs sending notifications" do
activity: activity activity: activity
) )
assert Impl.perform(notif) == [:ok, :ok] assert Impl.perform(notif) == {:ok, [:ok, :ok]}
end end
@tag capture_log: true @tag capture_log: true
test "returns error if notif does not match " do test "returns error if notif does not match " do
assert Impl.perform(%{}) == :error assert Impl.perform(%{}) == {:error, :unknown_type}
end end
test "successful message sending" do test "successful message sending" do

View file

@ -28,6 +28,42 @@ defmodule Pleroma.Web.StreamerTest do
{:ok, %{user: user, notify: notify}} {:ok, %{user: user, notify: notify}}
end end
test "it streams the user's post in the 'user' stream", %{user: user} do
task =
Task.async(fn ->
assert_receive {:text, _}, @streamer_timeout
end)
Streamer.add_socket(
"user",
%{transport_pid: task.pid, assigns: %{user: user}}
)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
Streamer.stream("user", activity)
Task.await(task)
end
test "it streams boosts of the user in the 'user' stream", %{user: user} do
task =
Task.async(fn ->
assert_receive {:text, _}, @streamer_timeout
end)
Streamer.add_socket(
"user",
%{transport_pid: task.pid, assigns: %{user: user}}
)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user)
Streamer.stream("user", announce)
Task.await(task)
end
test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
task = task =
Task.async(fn -> Task.async(fn ->

View file

@ -95,6 +95,30 @@ test "requires 'follow' or 'write:follows' permissions" do
end end
end end
end end
test "it imports follows with different nickname variations", %{conn: conn} do
[user2, user3, user4, user5, user6] = insert_list(5, :user)
identifiers =
[
user2.ap_id,
user3.nickname,
" ",
"@" <> user4.nickname,
user5.nickname <> "@localhost",
"@" <> user6.nickname <> "@localhost"
]
|> Enum.join("\n")
response =
conn
|> post("/api/pleroma/follow_import", %{"list" => identifiers})
|> json_response(:ok)
assert response == "job started"
assert [{:ok, job_result}] = ObanHelpers.perform_all()
assert job_result == [user2, user3, user4, user5, user6]
end
end end
describe "POST /api/pleroma/blocks_import" do describe "POST /api/pleroma/blocks_import" do
@ -136,6 +160,29 @@ test "it imports blocks users from file", %{user: user1, conn: conn} do
) )
end end
end end
test "it imports blocks with different nickname variations", %{conn: conn} do
[user2, user3, user4, user5, user6] = insert_list(5, :user)
identifiers =
[
user2.ap_id,
user3.nickname,
"@" <> user4.nickname,
user5.nickname <> "@localhost",
"@" <> user6.nickname <> "@localhost"
]
|> Enum.join(" ")
response =
conn
|> post("/api/pleroma/blocks_import", %{"list" => identifiers})
|> json_response(:ok)
assert response == "job started"
assert [{:ok, job_result}] = ObanHelpers.perform_all()
assert job_result == [user2, user3, user4, user5, user6]
end
end end
describe "PUT /api/pleroma/notification_settings" do describe "PUT /api/pleroma/notification_settings" do