diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d8e7efc3..702c58180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed - Support pagination in conversations API - **Breaking**: SimplePolicy `:reject` and `:accept` allow deletions again +- Fix follower/blocks import when nicknames starts with @ ## [unreleased-patch] ### Fixed diff --git a/docs/installation/debian_based_en.md b/docs/installation/debian_based_en.md index fe2dbb92d..62d8733f7 100644 --- a/docs/installation/debian_based_en.md +++ b/docs/installation/debian_based_en.md @@ -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-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-tools` -* `erlang-parsetools` -* `erlang-eldap`, if you want to enable ldap authenticator -* `erlang-ssh` -* `erlang-xmerl` +* `erlang-nox` * `git` * `build-essential` @@ -50,7 +46,7 @@ sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb ```shell 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 diff --git a/docs/installation/debian_based_jp.md b/docs/installation/debian_based_jp.md index 7aa0bcc24..a3c4621d8 100644 --- a/docs/installation/debian_based_jp.md +++ b/docs/installation/debian_based_jp.md @@ -10,21 +10,17 @@ ### 必要なソフトウェア - PostgreSQL 9.6以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください) -- 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ユーザーでインストールしてください) - - erlang-dev -- erlang-tools -- erlang-parsetools -- erlang-eldap (LDAP認証を有効化するときのみ必要) -- erlang-ssh -- erlang-xmerl -- git -- build-essential +- `postgresql-contrib` 9.6以上 (同上) +- 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-nox` +- `git` +- `build-essential` #### このガイドで利用している追加パッケージ -- nginx (おすすめです。他のリバースプロキシを使う場合は、参考となる設定をこのリポジトリから探してください) -- certbot (または何らかのLet's Encrypt向けACMEクライアント) +- `nginx` (おすすめです。他のリバースプロキシを使う場合は、参考となる設定をこのリポジトリから探してください) +- `certbot` (または何らかのLet's Encrypt向けACMEクライアント) ### システムを準備する @@ -51,7 +47,7 @@ sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb * ElixirとErlangをインストールします、 ``` 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 (バックエンド) をインストールします diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex index 6ca6550bd..0f3ecf1ed 100644 --- a/lib/pleroma/config/loader.ex +++ b/lib/pleroma/config/loader.ex @@ -47,7 +47,7 @@ defmodule Pleroma.Config.Loader do @spec filter_group(atom(), keyword()) :: keyword() def filter_group(group, configs) do 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 diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index f4722f99d..c02b70e96 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -46,14 +46,6 @@ defmodule Pleroma.Config.TransferTask do with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do # 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} = (Repo.all(ConfigDB) ++ deleted_settings) |> Enum.map(&transform_and_merge/1) @@ -65,10 +57,20 @@ defmodule Pleroma.Config.TransferTask do 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 |> Enum.map(&update/1) |> Enum.uniq() - |> Enum.reject(&(&1 in reject_restart)) + |> Enum.reject(&(&1 in reject)) |> maybe_set_pleroma_last() |> Enum.each(&restart(started_applications, &1, Config.get(:env))) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 9574432f0..e678fd415 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -261,7 +261,7 @@ defmodule Pleroma.Object do 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), "Question" <- object.data["type"] do multiple = Map.has_key?(object.data, "anyOf") @@ -276,12 +276,15 @@ defmodule Pleroma.Object do option end) + voters = [actor | object.data["voters"] || []] |> Enum.uniq() + data = if multiple do Map.put(object.data, "anyOf", options) else Map.put(object.data, "oneOf", options) end + |> Map.put("voters", voters) object |> Object.change(%{data: data}) diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 4446562ac..8d2809bbb 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -45,11 +45,11 @@ defmodule Pleroma.Stats do end def init(_args) do - {:ok, get_stat_data()} + {:ok, calculate_stat_data()} end def handle_call(:force_update, _from, _state) do - new_stats = get_stat_data() + new_stats = calculate_stat_data() {:reply, new_stats, new_stats} end @@ -58,12 +58,12 @@ defmodule Pleroma.Stats do end def handle_cast(:run_update, _state) do - new_stats = get_stat_data() + new_stats = calculate_stat_data() {:noreply, new_stats} end - defp get_stat_data do + def calculate_stat_data do peers = from( u in User, @@ -77,7 +77,15 @@ defmodule Pleroma.Stats do status_count = Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count) - user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id) + users_query = + from(u in User, + where: u.deactivated != true, + where: u.local == true, + where: not is_nil(u.nickname), + where: not u.invisible + ) + + user_count = Repo.aggregate(users_query, :count, :id) %{ peers: peers, diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index bef4679cb..477237756 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1180,7 +1180,9 @@ defmodule Pleroma.User do end @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}) |> Repo.all() end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f644897c2..7bc80df5d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -118,9 +118,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def increase_poll_votes_if_vote(%{ "object" => %{"inReplyTo" => reply_ap_id, "name" => name}, - "type" => "Create" + "type" => "Create", + "actor" => actor }) do - Object.increase_vote_count(reply_ap_id, name) + Object.increase_vote_count(reply_ap_id, name, actor) end def increase_poll_votes_if_vote(_create_data), do: :noop diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 2effb74f8..ebe3071b0 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -17,12 +17,17 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do # - Add like to object # - Set up notification def handle(%{data: %{"type" => "Like"}} = object, meta) do - liked_object = Object.get_by_ap_id(object.data["object"]) - Utils.add_like_to_object(object, liked_object) + {:ok, result} = + Pleroma.Repo.transaction(fn -> + liked_object = Object.get_by_ap_id(object.data["object"]) + Utils.add_like_to_object(object, liked_object) - Notification.create_notifications(object) + Notification.create_notifications(object) - {:ok, object, meta} + {:ok, object, meta} + end) + + result end def handle(%{data: %{"type" => "Create", "object" => object_id}} = activity, meta) do diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 9e25f4c2f..5eb221668 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -121,8 +121,9 @@ defmodule Pleroma.Web.CommonAPI do end end - def repeat(id_or_ap_id, user, params \\ %{}) do - with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)}, + def repeat(id, user, params \\ %{}) do + with {_, %Activity{data: %{"type" => "Create"}} = activity} <- + {:find_activity, Activity.get_by_id(id)}, object <- Object.normalize(activity), announce_activity <- Utils.get_existing_announce(user.ap_id, object), public <- public_announce?(object, params) do @@ -137,8 +138,9 @@ defmodule Pleroma.Web.CommonAPI do end end - def unrepeat(id_or_ap_id, user) do - with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)} do + def unrepeat(id, user) do + with {_, %Activity{data: %{"type" => "Create"}} = activity} <- + {:find_activity, Activity.get_by_id(id)} do object = Object.normalize(activity) ActivityPub.unannounce(user, object) else @@ -195,8 +197,9 @@ defmodule Pleroma.Web.CommonAPI do end end - def unfavorite(id_or_ap_id, user) do - with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)} do + def unfavorite(id, user) do + with {_, %Activity{data: %{"type" => "Create"}} = activity} <- + {:find_activity, Activity.get_by_id(id)} do object = Object.normalize(activity) ActivityPub.unlike(user, object) else @@ -367,12 +370,12 @@ defmodule Pleroma.Web.CommonAPI do defp maybe_create_activity_expiration(result, _), do: result - def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do + def pin(id, %{ap_id: user_ap_id} = user) do with %Activity{ actor: ^user_ap_id, data: %{"type" => "Create"}, object: %Object{data: %{"type" => object_type}} - } = activity <- get_by_id_or_ap_id(id_or_ap_id), + } = activity <- Activity.get_by_id_with_object(id), true <- object_type in ["Note", "Article", "Question"], true <- Visibility.is_public?(activity), {:ok, _user} <- User.add_pinnned_activity(user, activity) do @@ -383,8 +386,8 @@ defmodule Pleroma.Web.CommonAPI do end end - def unpin(id_or_ap_id, user) do - with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), + def unpin(id, user) do + with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id), {:ok, _user} <- User.remove_pinnned_activity(user, activity) do {:ok, activity} else diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 7eec5aa09..945e63e22 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -22,24 +22,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do require Logger require Pleroma.Constants - # This is a hack for twidere. - def get_by_id_or_ap_id(id) do - activity = - with true <- FlakeId.flake_id?(id), - %Activity{} = activity <- Activity.get_by_id_with_object(id) do - activity - else - _ -> Activity.get_create_by_object_ap_id_with_object(id) - end - - activity && - if activity.data["type"] == "Create" do - activity - else - Activity.get_create_by_object_ap_id_with_object(activity.data["object"]) - end - end - def attachments_from_ids(%{"media_ids" => ids, "descriptions" => desc} = _) do attachments_from_ids_descs(ids, desc) end diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index fd904ef0a..f5803578d 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -72,19 +72,24 @@ defmodule Pleroma.Web.Federator do # actor shouldn't be acting on objects outside their own AP server. with {:ok, _user} <- ap_enabled_actor(params["actor"]), 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} else + {:correct_origin?, _} -> + Logger.debug("Origin containment failure for #{params["id"]}") + {:error, :origin_containment_failed} + %Activity{} -> Logger.debug("Already had #{params["id"]}") - :error + {:error, :already_present} - _e -> + e -> # Just drop those for now Logger.debug("Unhandled activity") Logger.debug(Jason.encode!(params, pretty: true)) - :error + {:error, e} end end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index e8e59ac66..5a92cebd8 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -293,7 +293,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @doc "POST /api/v1/accounts/:id/follow" def follow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do - {:error, :not_found} + {:error, "Can not follow yourself"} end def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do @@ -306,7 +306,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @doc "POST /api/v1/accounts/:id/unfollow" def unfollow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do - {:error, :not_found} + {:error, "Can not unfollow yourself"} end def unfollow(%{assigns: %{user: follower, account: followed}} = conn, _params) do @@ -356,14 +356,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do end @doc "POST /api/v1/follows" - def follows(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do - with {_, %User{} = followed} <- {:followed, User.get_cached_by_nickname(uri)}, - {_, true} <- {:followed, follower.id != followed.id}, - {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do - render(conn, "show.json", user: followed, for: follower) - else - {:followed, _} -> {:error, :not_found} - {:error, message} -> json_response(conn, :forbidden, %{error: message}) + def follows(conn, %{"uri" => uri}) do + case User.get_cached_by_nickname(uri) do + %User{} = user -> + conn + |> assign(:account, user) + |> follow(%{}) + + nil -> + {:error, :not_found} end end diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 397dd10e3..f6e4f7d66 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -127,7 +127,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do def create( %{assigns: %{user: user}} = conn, %{"status" => _, "scheduled_at" => scheduled_at} = params - ) do + ) + when not is_nil(scheduled_at) do params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"]) with {:far_enough, true} <- {:far_enough, ScheduledActivity.far_enough?(scheduled_at)}, diff --git a/lib/pleroma/web/mastodon_api/views/poll_view.ex b/lib/pleroma/web/mastodon_api/views/poll_view.ex index 40edbb213..59a5deb28 100644 --- a/lib/pleroma/web/mastodon_api/views/poll_view.ex +++ b/lib/pleroma/web/mastodon_api/views/poll_view.ex @@ -19,6 +19,7 @@ defmodule Pleroma.Web.MastodonAPI.PollView do expired: expired, multiple: multiple, votes_count: votes_count, + voters_count: (multiple || nil) && voters_count(object), options: options, voted: voted?(params), emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"]) @@ -62,6 +63,12 @@ defmodule Pleroma.Web.MastodonAPI.PollView do end) end + defp voters_count(%{data: %{"voters" => [_ | _] = voters}}) do + length(voters) + end + + defp voters_count(_), do: 0 + defp voted?(%{object: object} = opts) do if opts[:for] do existing_votes = Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object) diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index f1740a6e0..a9f893f7b 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -55,11 +55,12 @@ defmodule Pleroma.Web.Push.Impl do |> Jason.encode!() |> push_message(build_sub(subscription), gcm_api_key, subscription) end + |> (&{:ok, &1}).() end def perform(_) do Logger.warn("Unknown notification type") - :error + {:error, :unknown_type} end @doc "Push message to web" diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex index abfed21c8..f6160fa4d 100644 --- a/lib/pleroma/web/streamer/worker.ex +++ b/lib/pleroma/web/streamer/worker.ex @@ -158,24 +158,6 @@ defmodule Pleroma.Web.Streamer.Worker do should_send?(user, activity) 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 Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} -> send(transport_pid, {:text, StreamerView.render("conversation.json", participation)}) diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex index 7e04e9550..4853e7f4b 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex @@ -1,8 +1,8 @@ <%= case @mediaType do %> <% "audio" -> %> - + <% "video" -> %> - + <% _ -> %> -<%= @name %> +<%= @name %> <% end %> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index df5e5eedd..df0244795 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -1,12 +1,16 @@ -
id="selected" <% end %>> +
id="selected" <% end %>>

- <%= link format_date(@published), to: @link, class: "activity-link" %> + + +

<%= render("_user_card.html", %{user: @user}) %>
<%= if @title != "" do %>
open<% end %>> - <%= raw @title %> + <%= raw @title %>
<%= raw @content %>
<% else %> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex index 56f3a1524..977b894d3 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex @@ -1,10 +1,10 @@
- +
- <%= raw Formatter.emojify(@user.name, @user.emoji) %> + <%= raw Formatter.emojify(@user.name, @user.emoji) %> <%= @user.nickname %>
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 537f9f778..d5d5ce08f 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -199,15 +199,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do - with lines <- String.split(list, "\n"), - followed_identifiers <- - Enum.map(lines, fn line -> - String.split(line, ",") |> List.first() - end) - |> List.delete("Account address") do - User.follow_import(follower, followed_identifiers) - json(conn, "job started") - end + followed_identifiers = + list + |> String.split("\n") + |> Enum.map(&(&1 |> String.split(",") |> List.first())) + |> List.delete("Account address") + |> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@"))) + |> Enum.reject(&(&1 == "")) + + User.follow_import(follower, followed_identifiers) + json(conn, "job started") end def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do @@ -215,10 +216,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do - with blocked_identifiers <- String.split(list) do - User.blocks_import(blocker, blocked_identifiers) - json(conn, "job started") - end + blocked_identifiers = list |> String.split() |> Enum.map(&String.trim_leading(&1, "@")) + User.blocks_import(blocker, blocked_identifiers) + json(conn, "job started") end def change_password(%{assigns: %{user: user}} = conn, params) do diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 0f8ece2c4..57c3a9c3a 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -35,7 +35,7 @@ defmodule Pleroma.Workers.BackgroundWorker do _job ) do blocker = User.get_cached_by_id(blocker_id) - User.perform(:blocks_import, blocker, blocked_identifiers) + {:ok, User.perform(:blocks_import, blocker, blocked_identifiers)} end def perform( @@ -47,7 +47,7 @@ defmodule Pleroma.Workers.BackgroundWorker do _job ) do follower = User.get_cached_by_id(follower_id) - User.perform(:follow_import, follower, followed_identifiers) + {:ok, User.perform(:follow_import, follower, followed_identifiers)} end def perform(%{"op" => "media_proxy_preload", "message" => message}, _job) do diff --git a/test/config/transfer_task_test.exs b/test/config/transfer_task_test.exs index 00db0b686..473899d1d 100644 --- a/test/config/transfer_task_test.exs +++ b/test/config/transfer_task_test.exs @@ -16,6 +16,7 @@ defmodule Pleroma.Config.TransferTaskTest do refute Application.get_env(:pleroma, :test_key) refute Application.get_env(:idna, :test_key) refute Application.get_env(:quack, :test_key) + refute Application.get_env(:postgrex, :test_key) initial = Application.get_env(:logger, :level) ConfigDB.create(%{ @@ -36,6 +37,12 @@ defmodule Pleroma.Config.TransferTaskTest do value: [:test_value1, :test_value2] }) + ConfigDB.create(%{ + group: ":postgrex", + key: ":test_key", + value: :value + }) + ConfigDB.create(%{group: ":logger", key: ":level", value: :debug}) TransferTask.start_link([]) @@ -44,11 +51,13 @@ defmodule Pleroma.Config.TransferTaskTest do 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(:logger, :level) == :debug + assert Application.get_env(:postgrex, :test_key) == :value on_exit(fn -> Application.delete_env(:pleroma, :test_key) Application.delete_env(:idna, :test_key) Application.delete_env(:quack, :test_key) + Application.delete_env(:postgrex, :test_key) Application.put_env(:logger, :level, initial) end) end diff --git a/test/fixtures/config/temp.secret.exs b/test/fixtures/config/temp.secret.exs index f4686c101..dc950ca30 100644 --- a/test/fixtures/config/temp.secret.exs +++ b/test/fixtures/config/temp.secret.exs @@ -7,3 +7,5 @@ config :pleroma, :second_setting, key: "value2", key2: ["Activity"] config :quack, level: :info config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox + +config :postgrex, :json_library, Poison diff --git a/test/stat_test.exs b/test/stats_test.exs similarity index 86% rename from test/stat_test.exs rename to test/stats_test.exs index bccc1c8d0..c1aeb2c7f 100644 --- a/test/stat_test.exs +++ b/test/stats_test.exs @@ -2,11 +2,21 @@ # Copyright © 2017-2020 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.StateTest do +defmodule Pleroma.StatsTest do use Pleroma.DataCase import Pleroma.Factory alias Pleroma.Web.CommonAPI + describe "user count" do + test "it ignores internal users" do + _user = insert(:user, local: true) + _internal = insert(:user, local: true, nickname: nil) + _internal = Pleroma.Web.ActivityPub.Relay.get_actor() + + assert match?(%{stats: %{user_count: 1}}, Pleroma.Stats.calculate_stat_data()) + end + end + describe "status visibility count" do test "on new status" do user = insert(:user) diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs index 3dee4f082..04bc947a9 100644 --- a/test/tasks/config_test.exs +++ b/test/tasks/config_test.exs @@ -38,7 +38,7 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do on_exit(fn -> Application.put_env(:quack, :level, initial) end) end - test "settings are migrated to db" do + test "filtered settings are migrated to db" do assert Repo.all(ConfigDB) == [] Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") @@ -47,6 +47,7 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) 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: ":postgrex", key: ":json_library"}) assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]] assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]] diff --git a/test/user_test.exs b/test/user_test.exs index 65e118d6d..347c5be72 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -756,8 +756,8 @@ defmodule Pleroma.UserTest do ] {:ok, job} = User.follow_import(user1, identifiers) - result = ObanHelpers.perform(job) + assert {:ok, result} = ObanHelpers.perform(job) assert is_list(result) assert result == [user2, user3] end @@ -979,14 +979,26 @@ defmodule Pleroma.UserTest do ] {:ok, job} = User.blocks_import(user1, identifiers) - result = ObanHelpers.perform(job) + assert {:ok, result} = ObanHelpers.perform(job) assert is_list(result) assert result == [user2, user3] end end 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 actor = insert(:user) user = insert(:user, local: true) diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 86b3648ac..0f8860ec5 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -71,6 +71,33 @@ defmodule Pleroma.Web.CommonAPITest do end end + test "favoriting race condition" do + user = insert(:user) + users_serial = insert_list(10, :user) + users = insert_list(10, :user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "."}) + + users_serial + |> Enum.map(fn user -> + CommonAPI.favorite(user, activity.id) + end) + + object = Object.get_by_ap_id(activity.data["object"]) + assert object.data["like_count"] == 10 + + users + |> Enum.map(fn user -> + Task.async(fn -> + CommonAPI.favorite(user, activity.id) + end) + end) + |> Enum.map(&Task.await/1) + + object = Object.get_by_ap_id(activity.data["object"]) + assert object.data["like_count"] == 20 + end + test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) @@ -306,6 +333,16 @@ defmodule Pleroma.Web.CommonAPITest do {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user) end + test "can't repeat a repeat" do + user = insert(:user) + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"}) + + {:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user) + + refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user)) + end + test "repeating a status privately" do user = insert(:user) other_user = insert(:user) @@ -335,8 +372,8 @@ defmodule Pleroma.Web.CommonAPITest do other_user = insert(:user) {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"}) - {:ok, %Activity{} = activity, object} = CommonAPI.repeat(activity.id, user) - {:ok, ^activity, ^object} = CommonAPI.repeat(activity.id, user) + {:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user) + {:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user) end test "favoriting a status twice returns ok, but without the like activity" do @@ -410,7 +447,9 @@ defmodule Pleroma.Web.CommonAPITest do user = refresh_record(user) - assert {:ok, ^activity} = CommonAPI.unpin(activity.id, user) + id = activity.id + + assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user)) user = refresh_record(user) diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index b21445fe9..18a3b3b87 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -335,26 +335,6 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do end end - describe "get_by_id_or_ap_id/1" do - test "get activity by id" do - activity = insert(:note_activity) - %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.id) - assert note.id == activity.id - end - - test "get activity by ap_id" do - activity = insert(:note_activity) - %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.data["object"]) - assert note.id == activity.id - end - - test "get activity by object when type isn't `Create` " do - activity = insert(:like_activity) - %Pleroma.Activity{} = like = Utils.get_by_id_or_ap_id(activity.id) - assert like.data["object"] == activity.data["object"] - end - end - describe "to_master_date/1" do test "removes microseconds from date (NaiveDateTime)" do assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z" diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 59e53bb03..261518ef0 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -130,6 +130,9 @@ defmodule Pleroma.Web.FederatorTest do assert {:ok, job} = Federator.incoming_ap_doc(params) assert {:ok, _activity} = ObanHelpers.perform(job) + + assert {:ok, job} = Federator.incoming_ap_doc(params) + assert {:error, :already_present} = ObanHelpers.perform(job) end test "rejects incoming AP docs with incorrect origin" do @@ -148,7 +151,7 @@ defmodule Pleroma.Web.FederatorTest do } assert {:ok, job} = Federator.incoming_ap_doc(params) - assert :error = ObanHelpers.perform(job) + assert {:error, :origin_containment_failed} = ObanHelpers.perform(job) end test "it does not crash if MRF rejects the post" do @@ -164,7 +167,7 @@ defmodule Pleroma.Web.FederatorTest do |> Poison.decode!() assert {:ok, job} = Federator.incoming_ap_doc(params) - assert :error = ObanHelpers.perform(job) + assert {:error, _} = ObanHelpers.perform(job) end end end diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index 61c2697b2..8c428efee 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/web/mastodon_api/controllers/account_controller_test.exs @@ -681,17 +681,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "following / unfollowing errors", %{user: user, conn: conn} do # self 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 user = User.get_cached_by_id(user.id) 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 user = User.get_cached_by_id(user.id) 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 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow") diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index 162f7b1b2..85068edd0 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -302,6 +302,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do assert [] == Repo.all(Activity) end + test "ignores nil values", %{conn: conn} do + conn = + post(conn, "/api/v1/statuses", %{ + "status" => "not scheduled", + "scheduled_at" => nil + }) + + assert result = json_response(conn, 200) + assert Activity.get_by_id(result["id"]) + end + test "creates a scheduled activity with a media attachment", %{user: user, conn: conn} do scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) diff --git a/test/web/mastodon_api/views/poll_view_test.exs b/test/web/mastodon_api/views/poll_view_test.exs index 6211fa888..63b204387 100644 --- a/test/web/mastodon_api/views/poll_view_test.exs +++ b/test/web/mastodon_api/views/poll_view_test.exs @@ -43,7 +43,8 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do %{title: "why are you even asking?", votes_count: 0} ], voted: false, - votes_count: 0 + votes_count: 0, + voters_count: nil } result = PollView.render("show.json", %{object: object}) @@ -69,9 +70,20 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do } }) + voter = insert(:user) + 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 test "detects emoji" do diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index 9121d90e7..b2664bf28 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -63,12 +63,12 @@ defmodule Pleroma.Web.Push.ImplTest do activity: activity ) - assert Impl.perform(notif) == [:ok, :ok] + assert Impl.perform(notif) == {:ok, [:ok, :ok]} end @tag capture_log: true test "returns error if notif does not match " do - assert Impl.perform(%{}) == :error + assert Impl.perform(%{}) == {:error, :unknown_type} end test "successful message sending" do diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index eb082b79f..8b8d8af6c 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -28,6 +28,42 @@ defmodule Pleroma.Web.StreamerTest do {:ok, %{user: user, notify: notify}} 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 task = Task.async(fn -> diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 30e54bebd..b701239a0 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -95,6 +95,30 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do 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 describe "POST /api/pleroma/blocks_import" do @@ -136,6 +160,29 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do ) 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 describe "PUT /api/pleroma/notification_settings" do