Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into websearch
authorlain <lain@soykaf.club>
Mon, 23 Nov 2020 14:18:19 +0000 (15:18 +0100)
committerlain <lain@soykaf.club>
Mon, 23 Nov 2020 14:18:19 +0000 (15:18 +0100)
35 files changed:
CHANGELOG.md
Dockerfile
docs/API/admin_api.md
docs/API/differences_in_mastoapi_responses.md
lib/mix/pleroma.ex
lib/pleroma/activity.ex
lib/pleroma/application.ex
lib/pleroma/emails/admin_email.ex
lib/pleroma/user/search.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
lib/pleroma/web/activity_pub/side_effects.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/activity_pub/views/user_view.ex
lib/pleroma/web/api_spec/operations/account_operation.ex
lib/pleroma/web/api_spec/schemas/account.ex
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
lib/pleroma/web/metadata/providers/restrict_indexing.ex
lib/pleroma/web/rich_media/helpers.ex
lib/pleroma/workers/background_worker.ex
priv/gettext/he/LC_MESSAGES/errors.po
priv/repo/migrations/20200915095704_remove_background_jobs.exs [new file with mode: 0644]
test/fixtures/mastodon/application_actor.json [new file with mode: 0644]
test/pleroma/activity_test.exs
test/pleroma/config/deprecation_warnings_test.exs
test/pleroma/user_search_test.exs
test/pleroma/web/activity_pub/activity_pub_controller_test.exs
test/pleroma/web/activity_pub/activity_pub_test.exs
test/pleroma/web/activity_pub/mrf/media_proxy_warming_policy_test.exs
test/pleroma/web/admin_api/search_test.exs
test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
test/pleroma/web/metadata/providers/restrict_indexing_test.exs
test/pleroma/web/metadata_test.exs [deleted file]
test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs
test/support/factory.ex

index 598fd59e3dbf4da79c68b92865cbc634aaff6f44..f4ef66408574649af2c092a8d0662912f27afc46 100644 (file)
@@ -36,7 +36,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ### Fixed
 
-- <details>
+- Users with `is_discoverable` field set to false (default value) will appear in in-service search results but be hidden from external services (search bots etc.).
+
+<details>
   <summary>API Changes</summary>
   - Mastodon API: Current user is now included in conversation if it's the only participant.
   - Mastodon API: Fixed last_status.account being not filled with account data.
@@ -46,8 +48,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ### Changed
 
-- Fix ability to update Pleroma Chat push notifications with PUT /api/v1/push/subscription and alert type pleroma:chat_mention
-
 ### Fixed
 
 - Config generation: rename `Pleroma.Upload.Filter.ExifTool` to `Pleroma.Upload.Filter.Exiftool`.
@@ -55,6 +55,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - S3 Uploads with Elixir 1.11.
 - Emoji Reaction activity filtering from blocked and muted accounts.
 - Mix task pleroma.user delete_activities for source installations.
+- Fix ability to update Pleroma Chat push notifications with PUT /api/v1/push/subscription and alert type pleroma:chat_mention
+- Forwarded reports duplication from Pleroma instances.
+
+<details>
+  <summary>API</summary>
+- Statuses were not displayed for Mastodon forwarded reports.
+
+</details>
 
 ## [2.2.0] - 2020-11-12
 
@@ -72,7 +80,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Renamed `:await_up_timeout` in `:connections_pool` namespace to `:connect_timeout`, old name is deprecated.
 - Renamed `:timeout` in `pools` namespace to `:recv_timeout`, old name is deprecated.
 - The `discoverable` field in the `User` struct will now add a NOINDEX metatag to profile pages when false.
-- Users with the `discoverable` field set to false will not show up in searches.
+- Users with the `is_discoverable` field set to false will not show up in searches ([bug](https://git.pleroma.social/pleroma/pleroma/-/issues/2301)).
 - Minimum lifetime for ephmeral activities changed to 10 minutes and made configurable (`:min_lifetime` option).
 - Introduced optional dependencies on `ffmpeg`, `ImageMagick`, `exiftool` software packages. Please refer to `docs/installation/optional/media_graphics_packages.md`.
 - <details>
index a1dc9d05064e569aeeecef1abb4a1e1de1f7107a..b1b5171af458f40f2997e613b1225cda0d424389 100644 (file)
@@ -33,7 +33,7 @@ ARG DATA=/var/lib/pleroma
 
 RUN echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories &&\
        apk update &&\
-       apk add exiftool imagemagick ncurses postgresql-client &&\
+       apk add exiftool imagemagick libmagic ncurses postgresql-client &&\
        adduser --system --shell /bin/false --home ${HOME} pleroma &&\
        mkdir -p ${DATA}/uploads &&\
        mkdir -p ${DATA}/static &&\
index 19ac6a65f51e0dc49f08f87246f0a0a77bf50885..266f8cef8e97ba546708d17dc07b9c2ebdeec697 100644 (file)
@@ -554,7 +554,7 @@ Response:
   * `show_role`
   * `skip_thread_containment`
   * `fields`
-  * `discoverable`
+  * `is_discoverable`
   * `actor_type`
 
 * Responses:
index 843496482905868a7d312d51215c40a3b8ef8987..6b0ad85d13bf13166885ddd01dd2c7b6ad0a0aa6 100644 (file)
@@ -84,7 +84,7 @@ Has these additional fields under the `pleroma` object:
 
 - `show_role`: boolean, nullable, true when the user wants his role (e.g admin, moderator) to be shown
 - `no_rich_text` - boolean, nullable, true when html tags are stripped from all statuses requested from the API
-- `discoverable`: boolean, true when the user allows discovery of the account in search results and other services.
+- `discoverable`: boolean, true when the user allows external services (search bots) etc. to index / list the account (regardless of this setting, user will still appear in regular search results)
 - `actor_type`: string, the type of this account.
 
 ## Conversations
@@ -207,7 +207,7 @@ Additional parameters can be added to the JSON body/Form data:
 - `skip_thread_containment` - if true, skip filtering out broken threads
 - `allow_following_move` - if true, allows automatically follow moved following accounts
 - `pleroma_background_image` - sets the background image of the user. Can be set to "" (an empty string) to reset.
-- `discoverable` - if true, discovery of this account in search results and other services is allowed.
+- `discoverable` - if true, external services (search bots) etc. are allowed to index / list the account (regardless of this setting, user will still appear in regular search results).
 - `actor_type` - the type of this account.
 - `accepts_chat_messages` - if false, this account will reject all chat messages.
 
index 3de11efcec82064857994dac1d90ba810328f898..6df1cf538156a3ddf7bed446b9e36ed0f0e361d9 100644 (file)
@@ -19,6 +19,7 @@ defmodule Mix.Pleroma do
   def start_pleroma do
     Pleroma.Config.Holder.save_default()
     Pleroma.Config.Oban.warn()
+    Pleroma.Application.limiters_setup()
     Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
 
     if Pleroma.Config.get(:env) != :test do
index 553834da0b786f905f1544fc9feb395c66bc0285..8559ae6a97a388dd5356b3d1869310156f2b65ee 100644 (file)
@@ -356,4 +356,15 @@ defmodule Pleroma.Activity do
     actor = user_actor(activity)
     activity.id in actor.pinned_activities
   end
+
+  @spec get_by_object_ap_id_with_object(String.t()) :: t() | nil
+  def get_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do
+    ap_id
+    |> Queries.by_object_id()
+    |> with_preloaded_object()
+    |> first()
+    |> Repo.one()
+  end
+
+  def get_by_object_ap_id_with_object(_), do: nil
 end
index 17a241cdfddb628a3653997aa17cc8323fb79c5f..22936bd7f245e7f7c128b1c7581c0f87bd4d4d82 100644 (file)
@@ -57,6 +57,7 @@ defmodule Pleroma.Application do
     setup_instrumenters()
     load_custom_modules()
     Pleroma.Docs.JSON.compile()
+    limiters_setup()
 
     adapter = Application.get_env(:tesla, :adapter)
 
@@ -293,4 +294,10 @@ defmodule Pleroma.Application do
   end
 
   defp http_children(_, _), do: []
+
+  @spec limiters_setup() :: :ok
+  def limiters_setup do
+    [Pleroma.Web.RichMedia.Helpers, Pleroma.Web.MediaProxy]
+    |> Enum.each(&ConcurrentLimiter.new(&1, 1, 0))
+  end
 end
index 02274554fe285414a4b63ac631a177d397296f7c..d5757c12a6403e6b7d16a8c08396a9643703f0bd 100644 (file)
@@ -48,6 +48,9 @@ defmodule Pleroma.Emails.AdminEmail do
               status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, id)
               "<li><a href=\"#{status_url}\">#{status_url}</li>"
 
+            %{"id" => id} when is_binary(id) ->
+              "<li><a href=\"#{id}\">#{id}</li>"
+
             id when is_binary(id) ->
               "<li><a href=\"#{id}\">#{id}</li>"
           end)
index 2dab672112b9636c1e62fda0beb630f37d162216..f1761ef032d1fe26455e24ebad287aa5bf66a5f9 100644 (file)
@@ -85,7 +85,6 @@ defmodule Pleroma.User.Search do
     |> base_query(following)
     |> filter_blocked_user(for_user)
     |> filter_invisible_users()
-    |> filter_discoverable_users()
     |> filter_internal_users()
     |> filter_blocked_domains(for_user)
     |> fts_search(query_string)
@@ -163,10 +162,6 @@ defmodule Pleroma.User.Search do
     from(q in query, where: q.invisible == false)
   end
 
-  defp filter_discoverable_users(query) do
-    from(q in query, where: q.is_discoverable == true)
-  end
-
   defp filter_internal_users(query) do
     from(q in query, where: q.actor_type != "Application")
   end
index 35f71b7ae3df78f247c05c1bc48bff49d232d4aa..1c91bc07482b22ac3905512860537f5a009486d3 100644 (file)
@@ -123,7 +123,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       # Splice in the child object if we have one.
       activity = Maps.put_if_present(activity, :object, object)
 
-      BackgroundWorker.enqueue("fetch_data_for_activity", %{"activity_id" => activity.id})
+      ConcurrentLimiter.limit(Pleroma.Web.RichMedia.Helpers, fn ->
+        Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end)
+      end)
 
       {:ok, activity}
     else
@@ -332,15 +334,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   end
 
   @spec flag(map()) :: {:ok, Activity.t()} | {:error, any()}
-  def flag(
-        %{
-          actor: actor,
-          context: _context,
-          account: account,
-          statuses: statuses,
-          content: content
-        } = params
-      ) do
+  def flag(params) do
+    with {:ok, result} <- Repo.transaction(fn -> do_flag(params) end) do
+      result
+    end
+  end
+
+  defp do_flag(
+         %{
+           actor: actor,
+           context: _context,
+           account: account,
+           statuses: statuses,
+           content: content
+         } = params
+       ) do
     # only accept false as false value
     local = !(params[:local] == false)
     forward = !(params[:forward] == false)
@@ -358,7 +366,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
          {:ok, activity} <- insert(flag_data, local),
          {:ok, stripped_activity} <- strip_report_status_data(activity),
          _ <- notify_and_stream(activity),
-         :ok <- maybe_federate(stripped_activity) do
+         :ok <-
+           maybe_federate(stripped_activity) do
       User.all_superusers()
       |> Enum.filter(fn user -> not is_nil(user.email) end)
       |> Enum.each(fn superuser ->
@@ -368,6 +377,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       end)
 
       {:ok, activity}
+    else
+      {:error, error} -> Repo.rollback(error)
     end
   end
 
@@ -791,10 +802,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       where:
         fragment(
           """
-          ?->>'type' != 'Create'     -- This isn't a Create      
+          ?->>'type' != 'Create'     -- This isn't a Create
           OR ?->>'inReplyTo' is null -- this isn't a reply
-          OR ? && array_remove(?, ?) -- The recipient is us or one of our friends, 
-                                     -- unless they are the author (because authors 
+          OR ? && array_remove(?, ?) -- The recipient is us or one of our friends,
+                                     -- unless they are the author (because authors
                                      -- are also part of the recipients). This leads
                                      -- to a bug that self-replies by friends won't
                                      -- show up.
index 0fb05d3c4be9dafa2cee8427b0922b55e6dcc48d..816cc89bfe2f9799ff62303bb64ce83801648365 100644 (file)
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
 
   alias Pleroma.HTTP
   alias Pleroma.Web.MediaProxy
-  alias Pleroma.Workers.BackgroundWorker
 
   require Logger
 
@@ -17,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
     recv_timeout: 10_000
   ]
 
-  def perform(:prefetch, url) do
+  defp prefetch(url) do
     # Fetching only proxiable resources
     if MediaProxy.enabled?() and MediaProxy.url_proxiable?(url) do
       # If preview proxy is enabled, it'll also hit media proxy (so we're caching both requests)
@@ -25,17 +24,25 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
 
       Logger.debug("Prefetching #{inspect(url)} as #{inspect(prefetch_url)}")
 
-      HTTP.get(prefetch_url, [], @adapter_options)
+      if Pleroma.Config.get(:env) == :test do
+        fetch(prefetch_url)
+      else
+        ConcurrentLimiter.limit(MediaProxy, fn ->
+          Task.start(fn -> fetch(prefetch_url) end)
+        end)
+      end
     end
   end
 
-  def perform(:preload, %{"object" => %{"attachment" => attachments}} = _message) do
+  defp fetch(url), do: HTTP.get(url, [], @adapter_options)
+
+  defp preload(%{"object" => %{"attachment" => attachments}} = _message) do
     Enum.each(attachments, fn
       %{"url" => url} when is_list(url) ->
         url
         |> Enum.each(fn
           %{"href" => href} ->
-            BackgroundWorker.enqueue("media_proxy_prefetch", %{"url" => href})
+            prefetch(href)
 
           x ->
             Logger.debug("Unhandled attachment URL object #{inspect(x)}")
@@ -51,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
         %{"type" => "Create", "object" => %{"attachment" => attachments} = _object} = message
       )
       when is_list(attachments) and length(attachments) > 0 do
-    BackgroundWorker.enqueue("media_proxy_preload", %{"message" => message})
+    preload(message)
 
     {:ok, message}
   end
index bbff35c360fd9b6f85083530f2a04b32c5649f00..4d8fb721e9465dc4eb384d1bbe56f23e20e55b91 100644 (file)
@@ -24,7 +24,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.Push
   alias Pleroma.Web.Streamer
-  alias Pleroma.Workers.BackgroundWorker
 
   require Logger
 
@@ -191,7 +190,9 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
         Object.increase_replies_count(in_reply_to)
       end
 
-      BackgroundWorker.enqueue("fetch_data_for_activity", %{"activity_id" => activity.id})
+      ConcurrentLimiter.limit(Pleroma.Web.RichMedia.Helpers, fn ->
+        Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end)
+      end)
 
       meta =
         meta
index 46002bec28b34bb4f5a21d47ea073d7d55187a74..ea1c3a04a37c401143e6e26c9e1f470e361701bd 100644 (file)
@@ -702,14 +702,30 @@ defmodule Pleroma.Web.ActivityPub.Utils do
 
   def make_flag_data(_, _), do: %{}
 
-  defp build_flag_object(%{account: account, statuses: statuses} = _) do
-    [account.ap_id] ++ build_flag_object(%{statuses: statuses})
+  defp build_flag_object(%{account: account, statuses: statuses}) do
+    [account.ap_id | build_flag_object(%{statuses: statuses})]
   end
 
   defp build_flag_object(%{statuses: statuses}) do
     Enum.map(statuses || [], &build_flag_object/1)
   end
 
+  defp build_flag_object(%Activity{data: %{"id" => id}, object: %{data: data}}) do
+    activity_actor = User.get_by_ap_id(data["actor"])
+
+    %{
+      "type" => "Note",
+      "id" => id,
+      "content" => data["content"],
+      "published" => data["published"],
+      "actor" =>
+        AccountView.render(
+          "show.json",
+          %{user: activity_actor, skip_visibility_check: true}
+        )
+    }
+  end
+
   defp build_flag_object(act) when is_map(act) or is_binary(act) do
     id =
       case act do
@@ -720,22 +736,14 @@ defmodule Pleroma.Web.ActivityPub.Utils do
 
     case Activity.get_by_ap_id_with_object(id) do
       %Activity{} = activity ->
-        activity_actor = User.get_by_ap_id(activity.object.data["actor"])
-
-        %{
-          "type" => "Note",
-          "id" => activity.data["id"],
-          "content" => activity.object.data["content"],
-          "published" => activity.object.data["published"],
-          "actor" =>
-            AccountView.render(
-              "show.json",
-              %{user: activity_actor, skip_visibility_check: true}
-            )
-        }
-
-      _ ->
-        %{"id" => id, "deleted" => true}
+        build_flag_object(activity)
+
+      nil ->
+        if activity = Activity.get_by_object_ap_id_with_object(id) do
+          build_flag_object(activity)
+        else
+          %{"id" => id, "deleted" => true}
+        end
     end
   end
 
index 4dc45cde344873d1f6d74a6b0c4b9783b3fde6ed..93c9f436c4acb70478dfe9919281c6e3c8662c13 100644 (file)
@@ -110,6 +110,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
       "endpoints" => endpoints,
       "attachment" => fields,
       "tag" => emoji_tags,
+      # Note: key name is indeed "discoverable" (not an error)
       "discoverable" => user.is_discoverable,
       "capabilities" => capabilities
     }
index 05595bc2a8ae9cc2d62c31de96223c8166af3a2a..280100c3d13edd68383d97394ff4f268fa8acc15 100644 (file)
@@ -624,7 +624,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
           allOf: [BooleanLike],
           nullable: true,
           description:
-            "Discovery of this account in search results and other services is allowed."
+            "Discovery (listing, indexing) of this account by external services (search bots etc.) is allowed."
         },
         actor_type: ActorType
       },
index ca79f0747861b93bb63e5d40022878369ffad247..684f6fc92e3287ee61d780344162d2a9674859c1 100644 (file)
@@ -127,7 +127,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
               discoverable: %Schema{
                 type: :boolean,
                 description:
-                  "whether the user allows discovery of the account in search results and other services."
+                  "whether the user allows indexing / listing of the account by external services (search engines etc.)."
               },
               no_rich_text: %Schema{
                 type: :boolean,
index 7ed4603a40f6f450d7832280f5977e2d2c568d49..7011b7eb15a94694d1575dd81cdcb8d35a26d7a7 100644 (file)
@@ -208,7 +208,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
         if bot, do: {:ok, "Service"}, else: {:ok, "Person"}
       end)
       |> Maps.put_if_present(:actor_type, params[:actor_type])
+      # Note: param name is indeed :locked (not an error)
       |> Maps.put_if_present(:is_locked, params[:locked])
+      # Note: param name is indeed :discoverable (not an error)
       |> Maps.put_if_present(:is_discoverable, params[:discoverable])
 
     # What happens here:
index 900c2434de216363fb9243a91a654d9f7619983d..a08a04b4a92f590e4b270dafc1b8b3f1b1d0d217 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.Metadata.Providers.RestrictIndexing do
   @behaviour Pleroma.Web.Metadata.Providers.Provider
 
   @moduledoc """
-  Restricts indexing of remote users.
+  Restricts indexing of remote and/or non-discoverable users.
   """
 
   @impl true
index d67b594b57dd10a2edce2bc9362e8ff1b7dcd219..442bf99957a9aa952518f5777bbed9dff806bba4 100644 (file)
@@ -78,11 +78,6 @@ defmodule Pleroma.Web.RichMedia.Helpers do
 
   def fetch_data_for_activity(_), do: %{}
 
-  def perform(:fetch, %Activity{} = activity) do
-    fetch_data_for_activity(activity)
-    :ok
-  end
-
   def rich_media_get(url) do
     headers = [{"user-agent", Pleroma.Application.user_agent() <> "; Bot"}]
 
index 55b5a13d9e451950a5bbf8560a3b7e0e3371a3fd..0647c65ae2b25022e7639d8802ae1f6a8eb1b1c9 100644 (file)
@@ -3,9 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Workers.BackgroundWorker do
-  alias Pleroma.Activity
   alias Pleroma.User
-  alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy
 
   use Pleroma.Workers.WorkerHelper, queue: "background"
 
@@ -32,19 +30,6 @@ defmodule Pleroma.Workers.BackgroundWorker do
     {:ok, User.Import.perform(String.to_atom(op), user, identifiers)}
   end
 
-  def perform(%Job{args: %{"op" => "media_proxy_preload", "message" => message}}) do
-    MediaProxyWarmingPolicy.perform(:preload, message)
-  end
-
-  def perform(%Job{args: %{"op" => "media_proxy_prefetch", "url" => url}}) do
-    MediaProxyWarmingPolicy.perform(:prefetch, url)
-  end
-
-  def perform(%Job{args: %{"op" => "fetch_data_for_activity", "activity_id" => activity_id}}) do
-    activity = Activity.get_by_id(activity_id)
-    Pleroma.Web.RichMedia.Helpers.perform(:fetch, activity)
-  end
-
   def perform(%Job{
         args: %{"op" => "move_following", "origin_id" => origin_id, "target_id" => target_id}
       }) do
index 6d97b620f3cf898e7ecbf93341f9a627211cf543..7e251383f2745a84ce45f38b8f8374d2cc68a016 100644 (file)
@@ -3,14 +3,17 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2020-11-10 13:39+0000\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: Automatically generated\n"
-"Language-Team: none\n"
+"PO-Revision-Date: 2020-11-21 04:42+0000\n"
+"Last-Translator: Guy Sheffer <guysoft@gmail.com>\n"
+"Language-Team: Hebrew <https://translate.pleroma.social/projects/pleroma/"
+"pleroma/he/>\n"
 "Language: he\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Translate Toolkit 2.5.1\n"
+"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
+"n % 10 == 0) ? 2 : 3));\n"
+"X-Generator: Weblate 4.0.4\n"
 
 ## This file is a PO Template file.
 ##
@@ -23,264 +26,264 @@ msgstr ""
 ## effect: edit them in PO (`.po`) files instead.
 ## From Ecto.Changeset.cast/4
 msgid "can't be blank"
-msgstr ""
+msgstr "לא יכול להיות ריק"
 
 ## From Ecto.Changeset.unique_constraint/3
 msgid "has already been taken"
-msgstr ""
+msgstr "כבר נלקח"
 
 ## From Ecto.Changeset.put_change/3
 msgid "is invalid"
-msgstr ""
+msgstr "אינו תקני"
 
 ## From Ecto.Changeset.validate_format/3
 msgid "has invalid format"
-msgstr ""
+msgstr "תבנית אינה תקנית"
 
 ## From Ecto.Changeset.validate_subset/3
 msgid "has an invalid entry"
-msgstr ""
+msgstr "בעל.ה רשומה לא חוקית"
 
 ## From Ecto.Changeset.validate_exclusion/3
 msgid "is reserved"
-msgstr ""
+msgstr "הינו שמור"
 
 ## From Ecto.Changeset.validate_confirmation/3
 msgid "does not match confirmation"
-msgstr ""
+msgstr "אינו תורם את האימות"
 
 ## From Ecto.Changeset.no_assoc_constraint/3
 msgid "is still associated with this entry"
-msgstr ""
+msgstr "עדיין משויך לרשומה זו"
 
 msgid "are still associated with this entry"
-msgstr ""
+msgstr "עדיין משויכים לרשומה זו"
 
 ## From Ecto.Changeset.validate_length/3
 msgid "should be %{count} character(s)"
 msgid_plural "should be %{count} character(s)"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "אחד"
+msgstr[1] "שני"
+msgstr[2] "בודדים"
+msgstr[3] "אחר"
 
 msgid "should have %{count} item(s)"
 msgid_plural "should have %{count} item(s)"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "אחד"
+msgstr[1] "שני"
+msgstr[2] "בודדים"
+msgstr[3] "אחר"
 
 msgid "should be at least %{count} character(s)"
 msgid_plural "should be at least %{count} character(s)"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "אחד"
+msgstr[1] "שנים"
+msgstr[2] "בודדים"
+msgstr[3] "אחר"
 
 msgid "should have at least %{count} item(s)"
 msgid_plural "should have at least %{count} item(s)"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "אחד"
+msgstr[1] "שניים"
+msgstr[2] "בודדים"
+msgstr[3] "אחר"
 
 msgid "should be at most %{count} character(s)"
 msgid_plural "should be at most %{count} character(s)"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "אחד"
+msgstr[1] "שניים"
+msgstr[2] "בודדים"
+msgstr[3] "אחר"
 
 msgid "should have at most %{count} item(s)"
 msgid_plural "should have at most %{count} item(s)"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "אחד"
+msgstr[1] "שניים"
+msgstr[2] "בודדים"
+msgstr[3] "אחר"
 
 ## From Ecto.Changeset.validate_number/3
 msgid "must be less than %{number}"
-msgstr ""
+msgstr "חייב להיות מתחת ל-%{number}"
 
 msgid "must be greater than %{number}"
-msgstr ""
+msgstr "חייב להיות מעל ל-%{number}"
 
 msgid "must be less than or equal to %{number}"
-msgstr ""
+msgstr "חייב להיות שווה ל-%{number}"
 
 msgid "must be greater than or equal to %{number}"
-msgstr ""
+msgstr "חייב להיות גדול או שווה ל-%{number}"
 
 msgid "must be equal to %{number}"
-msgstr ""
+msgstr "חייב להיות שווה ל-%{number}"
 
 #: lib/pleroma/web/common_api/common_api.ex:505
 #, elixir-format
 msgid "Account not found"
-msgstr ""
+msgstr "חשבון לא נמצא"
 
 #: lib/pleroma/web/common_api/common_api.ex:339
 #, elixir-format
 msgid "Already voted"
-msgstr ""
+msgstr "הצבעה כבר התבצעה"
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:359
 #, elixir-format
 msgid "Bad request"
-msgstr ""
+msgstr "בקשה שגוייה"
 
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:426
 #, elixir-format
 msgid "Can't delete object"
-msgstr ""
+msgstr "לא ניתן למחוק אובייקט"
 
 #: lib/pleroma/web/controller_helper.ex:105
 #: lib/pleroma/web/controller_helper.ex:111
 #, elixir-format
 msgid "Can't display this activity"
-msgstr ""
+msgstr "לא ניתן להציג פעילות"
 
 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:285
 #, elixir-format
 msgid "Can't find user"
-msgstr ""
+msgstr "לא ניתן למצוא משתמש"
 
 #: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:61
 #, elixir-format
 msgid "Can't get favorites"
-msgstr ""
+msgstr "לא ניתן למצוא מועדפים"
 
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
 #, elixir-format
 msgid "Can't like object"
-msgstr ""
+msgstr "לא ניתן לעשות לחבב אובייקט"
 
 #: lib/pleroma/web/common_api/utils.ex:563
 #, elixir-format
 msgid "Cannot post an empty status without attachments"
-msgstr ""
+msgstr "לא ניתן לשלוח סטטוס ריק ללא קבצים מצורפים"
 
 #: lib/pleroma/web/common_api/utils.ex:511
 #, elixir-format
 msgid "Comment must be up to %{max_size} characters"
-msgstr ""
+msgstr "תגובה חייבת להיות עד %{max_size} תווים"
 
 #: lib/pleroma/config/config_db.ex:191
 #, elixir-format
 msgid "Config with params %{params} not found"
-msgstr ""
+msgstr "הגדרה עם פרמטר %{params} לא נמצאה"
 
 #: lib/pleroma/web/common_api/common_api.ex:181
 #: lib/pleroma/web/common_api/common_api.ex:185
 #, elixir-format
 msgid "Could not delete"
-msgstr ""
+msgstr "לא ניתן למחוק"
 
 #: lib/pleroma/web/common_api/common_api.ex:231
 #, elixir-format
 msgid "Could not favorite"
-msgstr ""
+msgstr "לא ניתן לחבב"
 
 #: lib/pleroma/web/common_api/common_api.ex:453
 #, elixir-format
 msgid "Could not pin"
-msgstr ""
+msgstr "לא ניתן לנעוץ"
 
 #: lib/pleroma/web/common_api/common_api.ex:278
 #, elixir-format
 msgid "Could not unfavorite"
-msgstr ""
+msgstr "לא ניתן להסיר חיבוב"
 
 #: lib/pleroma/web/common_api/common_api.ex:463
 #, elixir-format
 msgid "Could not unpin"
-msgstr ""
+msgstr "לא ניתן לבטל נעיצה"
 
 #: lib/pleroma/web/common_api/common_api.ex:216
 #, elixir-format
 msgid "Could not unrepeat"
-msgstr ""
+msgstr "לא ניתן לבטל חזרה"
 
 #: lib/pleroma/web/common_api/common_api.ex:512
 #: lib/pleroma/web/common_api/common_api.ex:521
 #, elixir-format
 msgid "Could not update state"
-msgstr ""
+msgstr "לא ניתן לעדכן מצב"
 
 #: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:207
 #, elixir-format
 msgid "Error."
-msgstr ""
+msgstr "שגיאה."
 
 #: lib/pleroma/web/twitter_api/twitter_api.ex:106
 #, elixir-format
 msgid "Invalid CAPTCHA"
-msgstr ""
+msgstr "CAPTCHA לא תקין"
 
 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:116
 #: lib/pleroma/web/oauth/oauth_controller.ex:568
 #, elixir-format
 msgid "Invalid credentials"
-msgstr ""
+msgstr "נתוני אימות לא נכונים"
 
 #: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
 #, elixir-format
 msgid "Invalid credentials."
-msgstr ""
+msgstr "נתוני אימות לא נכונים."
 
 #: lib/pleroma/web/common_api/common_api.ex:355
 #, elixir-format
 msgid "Invalid indices"
-msgstr ""
+msgstr "אינדקס לא תקין"
 
 #: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:29
 #, elixir-format
 msgid "Invalid parameters"
-msgstr ""
+msgstr "פרמטרים לא תקינים"
 
 #: lib/pleroma/web/common_api/utils.ex:414
 #, elixir-format
 msgid "Invalid password."
-msgstr ""
+msgstr "סיסמה לא תקינה."
 
 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220
 #, elixir-format
 msgid "Invalid request"
-msgstr ""
+msgstr "בקשה לא תקינה"
 
 #: lib/pleroma/web/twitter_api/twitter_api.ex:109
 #, elixir-format
 msgid "Kocaptcha service unavailable"
-msgstr ""
+msgstr "שירות Kocaptcha לא זמין"
 
 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112
 #, elixir-format
 msgid "Missing parameters"
-msgstr ""
+msgstr "פרמטרים חסרים"
 
 #: lib/pleroma/web/common_api/utils.ex:547
 #, elixir-format
 msgid "No such conversation"
-msgstr ""
+msgstr "שיחה לא קיימת"
 
 #: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:388
 #: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:414 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:456
 #, elixir-format
 msgid "No such permission_group"
-msgstr ""
+msgstr "permission_group לא קיים"
 
 #: lib/pleroma/plugs/uploaded_media.ex:84
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:486 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:11
 #: lib/pleroma/web/feed/user_controller.ex:71 lib/pleroma/web/ostatus/ostatus_controller.ex:143
 #, elixir-format
 msgid "Not found"
-msgstr ""
+msgstr "לא נמצא"
 
 #: lib/pleroma/web/common_api/common_api.ex:331
 #, elixir-format
 msgid "Poll's author can't vote"
-msgstr ""
+msgstr "מחבר הסקר לא יכול.ה להצביע"
 
 #: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
 #: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
@@ -288,215 +291,215 @@ msgstr ""
 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
 #, elixir-format
 msgid "Record not found"
-msgstr ""
+msgstr "רשומה לא נמצאה"
 
 #: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:35
 #: lib/pleroma/web/feed/user_controller.ex:77 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:36
 #: lib/pleroma/web/ostatus/ostatus_controller.ex:149
 #, elixir-format
 msgid "Something went wrong"
-msgstr ""
+msgstr "משהו השתבש"
 
 #: lib/pleroma/web/common_api/activity_draft.ex:107
 #, elixir-format
 msgid "The message visibility must be direct"
-msgstr ""
+msgstr "הנראות של ההודעה חייבת להיות ישירה"
 
 #: lib/pleroma/web/common_api/utils.ex:573
 #, elixir-format
 msgid "The status is over the character limit"
-msgstr ""
+msgstr "הסטטוס מעל להגבלת התווים"
 
 #: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
 #, elixir-format
 msgid "This resource requires authentication."
-msgstr ""
+msgstr "המשאב הזה דורש הרשאה."
 
 #: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
 #, elixir-format
 msgid "Throttled"
-msgstr ""
+msgstr "מושנק"
 
 #: lib/pleroma/web/common_api/common_api.ex:356
 #, elixir-format
 msgid "Too many choices"
-msgstr ""
+msgstr "יותר מדיי אפשרויות"
 
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:443
 #, elixir-format
 msgid "Unhandled activity type"
-msgstr ""
+msgstr "אין התמודדות לסוג הפעילות"
 
 #: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:485
 #, elixir-format
 msgid "You can't revoke your own admin status."
-msgstr ""
+msgstr "לא ניתן לבטל את הרשאת המנהל של עצמך."
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:221
 #: lib/pleroma/web/oauth/oauth_controller.ex:308
 #, elixir-format
 msgid "Your account is currently disabled"
-msgstr ""
+msgstr "החשבון שלך כרגע מבוטל"
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:183
 #: lib/pleroma/web/oauth/oauth_controller.ex:331
 #, elixir-format
 msgid "Your login is missing a confirmed e-mail address"
-msgstr ""
+msgstr "חסר לחשבון שלך כתובת דואר אלקטרוני מאושר"
 
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:390
 #, elixir-format
 msgid "can't read inbox of %{nickname} as %{as_nickname}"
-msgstr ""
+msgstr "לא ניתן לקרוא את הדואר הנכנס של %{nickname} בתור %{as_nickname}"
 
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:473
 #, elixir-format
 msgid "can't update outbox of %{nickname} as %{as_nickname}"
-msgstr ""
+msgstr "לא ניתן לעדכן את חשבון הדואר היוצא של %{nickname} בתור %{as_nickname}"
 
 #: lib/pleroma/web/common_api/common_api.ex:471
 #, elixir-format
 msgid "conversation is already muted"
-msgstr ""
+msgstr "שיחה כבר הושתקה"
 
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:314
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:492
 #, elixir-format
 msgid "error"
-msgstr ""
+msgstr "שגיאה"
 
 #: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:32
 #, elixir-format
 msgid "mascots can only be images"
-msgstr ""
+msgstr "קמע יכול להיות רק תמונות"
 
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:62
 #, elixir-format
 msgid "not found"
-msgstr ""
+msgstr "לא נמצא"
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:394
 #, elixir-format
 msgid "Bad OAuth request."
-msgstr ""
+msgstr "בקשת OAuth שגוייה."
 
 #: lib/pleroma/web/twitter_api/twitter_api.ex:115
 #, elixir-format
 msgid "CAPTCHA already used"
-msgstr ""
+msgstr "כבר נעשה שימוש ב-CAPTCHA הזה"
 
 #: lib/pleroma/web/twitter_api/twitter_api.ex:112
 #, elixir-format
 msgid "CAPTCHA expired"
-msgstr ""
+msgstr "פג תוקף CAPTCHA"
 
 #: lib/pleroma/plugs/uploaded_media.ex:57
 #, elixir-format
 msgid "Failed"
-msgstr ""
+msgstr "נכשל"
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:410
 #, elixir-format
 msgid "Failed to authenticate: %{message}."
-msgstr ""
+msgstr "נכשל האימות: %{message}."
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:441
 #, elixir-format
 msgid "Failed to set up user account."
-msgstr ""
+msgstr "הגדרת חשבון משתמש נכשלה."
 
 #: lib/pleroma/plugs/oauth_scopes_plug.ex:38
 #, elixir-format
 msgid "Insufficient permissions: %{permissions}."
-msgstr ""
+msgstr "אין מספיק הרשאות: %{permissions}."
 
 #: lib/pleroma/plugs/uploaded_media.ex:104
 #, elixir-format
 msgid "Internal Error"
-msgstr ""
+msgstr "שגיאה פנימית"
 
 #: lib/pleroma/web/oauth/fallback_controller.ex:22
 #: lib/pleroma/web/oauth/fallback_controller.ex:29
 #, elixir-format
 msgid "Invalid Username/Password"
-msgstr ""
+msgstr "שם משתמש/סיסמה שגויים"
 
 #: lib/pleroma/web/twitter_api/twitter_api.ex:118
 #, elixir-format
 msgid "Invalid answer data"
-msgstr ""
+msgstr "תשובה שגוייה למידע"
 
 #: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:33
 #, elixir-format
 msgid "Nodeinfo schema version not handled"
-msgstr ""
+msgstr "Nodeinfo של של גרסת הסכמה לא ניתן לטיפול"
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:172
 #, elixir-format
 msgid "This action is outside the authorized scopes"
-msgstr ""
+msgstr "הפעולה הזו מחוץ לתחומי ההרשאות"
 
 #: lib/pleroma/web/oauth/fallback_controller.ex:14
 #, elixir-format
 msgid "Unknown error, please check the details and try again."
-msgstr ""
+msgstr "שגיאה לא ידועה, יש לבדוק את פרטים ולנסות שוב."
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:119
 #: lib/pleroma/web/oauth/oauth_controller.ex:158
 #, elixir-format
 msgid "Unlisted redirect_uri."
-msgstr ""
+msgstr "ניתב redirect_uri לא רשום."
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:390
 #, elixir-format
 msgid "Unsupported OAuth provider: %{provider}."
-msgstr ""
+msgstr "ספק OAuth לא נתמך: %{provider}."
 
 #: lib/pleroma/uploaders/uploader.ex:72
 #, elixir-format
 msgid "Uploader callback timeout"
-msgstr ""
+msgstr "קריאה חזרה של מעלה עברה את הזמן הקצוב"
 
 #: lib/pleroma/web/uploader_controller.ex:23
 #, elixir-format
 msgid "bad request"
-msgstr ""
+msgstr "בקשה שגוייה"
 
 #: lib/pleroma/web/twitter_api/twitter_api.ex:103
 #, elixir-format
 msgid "CAPTCHA Error"
-msgstr ""
+msgstr "שגיאת CAPTCHA"
 
 #: lib/pleroma/web/common_api/common_api.ex:290
 #, elixir-format
 msgid "Could not add reaction emoji"
-msgstr ""
+msgstr "לא ניתן להוסיף סמלון תגובה"
 
 #: lib/pleroma/web/common_api/common_api.ex:301
 #, elixir-format
 msgid "Could not remove reaction emoji"
-msgstr ""
+msgstr "לא ניתן להסיר סמלון תגובה"
 
 #: lib/pleroma/web/twitter_api/twitter_api.ex:129
 #, elixir-format
 msgid "Invalid CAPTCHA (Missing parameter: %{name})"
-msgstr ""
+msgstr "CAPTCHA לא תקני (חסר פרמטר: %{name})"
 
 #: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
 #, elixir-format
 msgid "List not found"
-msgstr ""
+msgstr "רשימה לא נמצאה"
 
 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
 #, elixir-format
 msgid "Missing parameter: %{name}"
-msgstr ""
+msgstr "חסר פרמטר: %{name}"
 
 #: lib/pleroma/web/oauth/oauth_controller.ex:210
 #: lib/pleroma/web/oauth/oauth_controller.ex:321
 #, elixir-format
 msgid "Password reset is required"
-msgstr ""
+msgstr "נדרש איפוס סיסמה"
 
 #: lib/pleroma/tests/auth_test_controller.ex:9
 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
@@ -533,64 +536,64 @@ msgstr ""
 #: lib/pleroma/web/uploader_controller.ex:6 lib/pleroma/web/web_finger/web_finger_controller.ex:6
 #, elixir-format
 msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
-msgstr ""
+msgstr "הפרת אבטחה: OAuth בבדיקת המתחם לא נבדקה או דולגה במכוון."
 
 #: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
 #, elixir-format
 msgid "Two-factor authentication enabled, you must use a access token."
-msgstr ""
+msgstr "אימות דו-שלבי הופעל, יש להזין אסימון כניסה."
 
 #: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
 #, elixir-format
 msgid "Unexpected error occurred while adding file to pack."
-msgstr ""
+msgstr "אירעה שגיאה לא צפויה בזמן הוספת הקובץ לחבילה."
 
 #: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:138
 #, elixir-format
 msgid "Unexpected error occurred while creating pack."
-msgstr ""
+msgstr "אירעה שגיאה לא צפויה בזמן יצירת חבילה."
 
 #: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:278
 #, elixir-format
 msgid "Unexpected error occurred while removing file from pack."
-msgstr ""
+msgstr "אירעה שגיאה לא צפויה בזמן הסרת הקובץ מהחבילה."
 
 #: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:250
 #, elixir-format
 msgid "Unexpected error occurred while updating file in pack."
-msgstr ""
+msgstr "אירעה שגיאה לא צפויה בזמן עדכון הקובץ מהחבילה."
 
 #: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:179
 #, elixir-format
 msgid "Unexpected error occurred while updating pack metadata."
-msgstr ""
+msgstr "אירעה שגיאה לא צפויה בזמן עדכון מטא-דאטה של החבילה."
 
 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
 #, elixir-format
 msgid "Web push subscription is disabled on this Pleroma instance"
-msgstr ""
+msgstr "הרשמה לעדכון ווב בדחיפה מבוטלת בשרת פלרומה זה"
 
 #: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
 #, elixir-format
 msgid "You can't revoke your own admin/moderator status."
-msgstr ""
+msgstr "לא ניתן לשלול את סטטוס האדמין/מנהל של עצמך."
 
 #: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
 #, elixir-format
 msgid "authorization required for timeline view"
-msgstr ""
+msgstr "הרשאה דרושה על מנת לצפות בציר הזמן"
 
 #: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
 #, elixir-format
 msgid "Access denied"
-msgstr ""
+msgstr "גישה נדחית"
 
 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
 #, elixir-format
 msgid "This API requires an authenticated user"
-msgstr ""
+msgstr "ה-API דורש הרשאת משתמש"
 
 #: lib/pleroma/plugs/user_is_admin_plug.ex:21
 #, elixir-format
 msgid "User is not an admin."
-msgstr ""
+msgstr "משתמש אינו מנהל."
diff --git a/priv/repo/migrations/20200915095704_remove_background_jobs.exs b/priv/repo/migrations/20200915095704_remove_background_jobs.exs
new file mode 100644 (file)
index 0000000..9785bfb
--- /dev/null
@@ -0,0 +1,22 @@
+defmodule Pleroma.Repo.Migrations.RemoveBackgroundJobs do
+  use Ecto.Migration
+
+  import Ecto.Query, only: [from: 2]
+
+  def up do
+    from(j in "oban_jobs",
+      where:
+        j.queue == ^"background" and
+          fragment("?->>'op'", j.args) in ^[
+            "fetch_data_for_activity",
+            "media_proxy_prefetch",
+            "media_proxy_preload"
+          ] and
+          j.worker == ^"Pleroma.Workers.BackgroundWorker",
+      select: [:id]
+    )
+    |> Pleroma.Repo.delete_all()
+  end
+
+  def down, do: :ok
+end
diff --git a/test/fixtures/mastodon/application_actor.json b/test/fixtures/mastodon/application_actor.json
new file mode 100644 (file)
index 0000000..2089ea0
--- /dev/null
@@ -0,0 +1,67 @@
+{
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    "https://w3id.org/security/v1",
+    {
+      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+      "toot": "http://joinmastodon.org/ns#",
+      "featured": {
+        "@id": "toot:featured",
+        "@type": "@id"
+      },
+      "alsoKnownAs": {
+        "@id": "as:alsoKnownAs",
+        "@type": "@id"
+      },
+      "movedTo": {
+        "@id": "as:movedTo",
+        "@type": "@id"
+      },
+      "schema": "http://schema.org#",
+      "PropertyValue": "schema:PropertyValue",
+      "value": "schema:value",
+      "IdentityProof": "toot:IdentityProof",
+      "discoverable": "toot:discoverable",
+      "Device": "toot:Device",
+      "Ed25519Signature": "toot:Ed25519Signature",
+      "Ed25519Key": "toot:Ed25519Key",
+      "Curve25519Key": "toot:Curve25519Key",
+      "EncryptedMessage": "toot:EncryptedMessage",
+      "publicKeyBase64": "toot:publicKeyBase64",
+      "deviceId": "toot:deviceId",
+      "claim": {
+        "@type": "@id",
+        "@id": "toot:claim"
+      },
+      "fingerprintKey": {
+        "@type": "@id",
+        "@id": "toot:fingerprintKey"
+      },
+      "identityKey": {
+        "@type": "@id",
+        "@id": "toot:identityKey"
+      },
+      "devices": {
+        "@type": "@id",
+        "@id": "toot:devices"
+      },
+      "messageFranking": "toot:messageFranking",
+      "messageType": "toot:messageType",
+      "cipherText": "toot:cipherText"
+    }
+  ],
+  "id": "https://{{DOMAIN}}/actor",
+  "type": "Application",
+  "inbox": "https://{{DOMAIN}}/actor/inbox",
+  "preferredUsername": "{{DOMAIN}}",
+  "url": "https://{{DOMAIN}}/about/more?instance_actor=true",
+  "manuallyApprovesFollowers": true,
+  "publicKey": {
+    "id": "https://{{DOMAIN}}/actor#main-key",
+    "owner": "https://{{DOMAIN}}/actor",
+    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAA0CA08AMIIBCgKCAQEAyi2T2FFZJgRPY+96YQrn\n6J6eF2P60J+nz+/pRc/acv/Nx+NLxxPyXby0F2s60MV7uALRQbBBnf7oNKCd/T4S\nvbr7UXMCWTdaJBpYubMKWT9uBlaUUkUfqL+WTV+IQnlcKtssQ4+AwrAKAZXza8ws\nZypevOsLHzayyEzztmm1KQC9GCUOITCLf7Q6qEhy8z/HuqLBEC0Own0pD7QsbfcS\no1peuZY7g1E/jJ9HR9GqJccMaR0H28KmJ7tT1Yzlyf5uZMRIdPxsoMR9sGLjR2B8\noegSwaf9SogR3ScP395Tt/9Ud1VVzuhpoS8Uy7jKSs+3CuLJsEGoMrib8VyOwadS\n9wIDAQAB\n-----END PUBLIC KEY-----\n"
+  },
+  "endpoints": {
+    "sharedInbox": "https://{{DOMAIN}}/inbox"
+  }
+}
index ee6a99cc36b76b638ca6e87f855915d81efcfb09..3e9fe209e7736c2bca2f25501e14781f55c07735 100644 (file)
@@ -231,4 +231,20 @@ defmodule Pleroma.ActivityTest do
 
     assert [%Activity{id: ^id1}, %Activity{id: ^id2}] = activities
   end
+
+  test "get_by_object_ap_id_with_object/1" do
+    user = insert(:user)
+    another = insert(:user)
+
+    {:ok, %{id: id, object: %{data: %{"id" => obj_id}}}} =
+      Pleroma.Web.CommonAPI.post(user, %{status: "cofe"})
+
+    Pleroma.Web.CommonAPI.favorite(another, id)
+
+    assert obj_id
+           |> Pleroma.Activity.Queries.by_object_id()
+           |> Repo.aggregate(:count, :id) == 2
+
+    assert %{id: ^id} = Activity.get_by_object_ap_id_with_object(obj_id)
+  end
 end
index 0cfed45557dd65ecd1d5159e508971d94f3082c8..f52629f8ab5842f4f921bc63ae812c9f69e69474 100644 (file)
@@ -12,7 +12,7 @@ defmodule Pleroma.Config.DeprecationWarningsTest do
   alias Pleroma.Config.DeprecationWarnings
 
   test "check_old_mrf_config/0" do
-    clear_config([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.NoOpPolicy)
+    clear_config([:instance, :rewrite_policy], [])
     clear_config([:instance, :mrf_transparency], true)
     clear_config([:instance, :mrf_transparency_exclusions], [])
 
index 31d787ffa0ed35e2ef817c99956a2ee1d5241e7d..de1df2e9c362264295c492b44426e285d29934bd 100644 (file)
@@ -65,12 +65,13 @@ defmodule Pleroma.UserSearchTest do
       assert found_user.id == user.id
     end
 
-    test "excludes users when discoverable is false" do
+    # Note: as in Mastodon, `is_discoverable` doesn't anyhow relate to user searchability
+    test "includes non-discoverable users in results" do
       insert(:user, %{nickname: "john 3000", is_discoverable: false})
       insert(:user, %{nickname: "john 3001"})
 
       users = User.search("john")
-      assert Enum.count(users) == 1
+      assert Enum.count(users) == 2
     end
 
     test "excludes service actors from results" do
index 31e48f87f6f9a49c3bb3826ebcbbcedc07f4f4d1..b577e25ddb7702994dfbb997571fb1e5a5d9d4ca 100644 (file)
@@ -799,6 +799,142 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
 
       assert json_response(ret_conn, 200)
     end
+
+    @tag capture_log: true
+    test "forwarded report", %{conn: conn} do
+      admin = insert(:user, is_admin: true)
+      actor = insert(:user, local: false)
+      remote_domain = URI.parse(actor.ap_id).host
+      reported_user = insert(:user)
+
+      note = insert(:note_activity, user: reported_user)
+
+      data = %{
+        "@context" => [
+          "https://www.w3.org/ns/activitystreams",
+          "https://#{remote_domain}/schemas/litepub-0.1.jsonld",
+          %{
+            "@language" => "und"
+          }
+        ],
+        "actor" => actor.ap_id,
+        "cc" => [
+          reported_user.ap_id
+        ],
+        "content" => "test",
+        "context" => "context",
+        "id" => "http://#{remote_domain}/activities/02be56cf-35e3-46b4-b2c6-47ae08dfee9e",
+        "nickname" => reported_user.nickname,
+        "object" => [
+          reported_user.ap_id,
+          %{
+            "actor" => %{
+              "actor_type" => "Person",
+              "approval_pending" => false,
+              "avatar" => "",
+              "confirmation_pending" => false,
+              "deactivated" => false,
+              "display_name" => "test user",
+              "id" => reported_user.id,
+              "local" => false,
+              "nickname" => reported_user.nickname,
+              "registration_reason" => nil,
+              "roles" => %{
+                "admin" => false,
+                "moderator" => false
+              },
+              "tags" => [],
+              "url" => reported_user.ap_id
+            },
+            "content" => "",
+            "id" => note.data["id"],
+            "published" => note.data["published"],
+            "type" => "Note"
+          }
+        ],
+        "published" => note.data["published"],
+        "state" => "open",
+        "to" => [],
+        "type" => "Flag"
+      }
+
+      conn
+      |> assign(:valid_signature, true)
+      |> put_req_header("content-type", "application/activity+json")
+      |> post("/users/#{reported_user.nickname}/inbox", data)
+      |> json_response(200)
+
+      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+
+      assert Pleroma.Repo.aggregate(Activity, :count, :id) == 2
+
+      ObanHelpers.perform_all()
+
+      Swoosh.TestAssertions.assert_email_sent(
+        to: {admin.name, admin.email},
+        html_body: ~r/Reported Account:/i
+      )
+    end
+
+    @tag capture_log: true
+    test "forwarded report from mastodon", %{conn: conn} do
+      admin = insert(:user, is_admin: true)
+      actor = insert(:user, local: false)
+      remote_domain = URI.parse(actor.ap_id).host
+      remote_actor = "https://#{remote_domain}/actor"
+      [reported_user, another] = insert_list(2, :user)
+
+      note = insert(:note_activity, user: reported_user)
+
+      Pleroma.Web.CommonAPI.favorite(another, note.id)
+
+      mock_json_body =
+        "test/fixtures/mastodon/application_actor.json"
+        |> File.read!()
+        |> String.replace("{{DOMAIN}}", remote_domain)
+
+      Tesla.Mock.mock(fn %{url: ^remote_actor} ->
+        %Tesla.Env{
+          status: 200,
+          body: mock_json_body,
+          headers: [{"content-type", "application/activity+json"}]
+        }
+      end)
+
+      data = %{
+        "@context" => "https://www.w3.org/ns/activitystreams",
+        "actor" => remote_actor,
+        "content" => "test report",
+        "id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8",
+        "nickname" => reported_user.nickname,
+        "object" => [
+          reported_user.ap_id,
+          note.data["object"]
+        ],
+        "type" => "Flag"
+      }
+
+      conn
+      |> assign(:valid_signature, true)
+      |> put_req_header("content-type", "application/activity+json")
+      |> post("/users/#{reported_user.nickname}/inbox", data)
+      |> json_response(200)
+
+      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+
+      flag_activity = "Flag" |> Pleroma.Activity.Queries.by_type() |> Pleroma.Repo.one()
+      reported_user_ap_id = reported_user.ap_id
+
+      [^reported_user_ap_id, flag_data] = flag_activity.data["object"]
+
+      Enum.each(~w(actor content id published type), &Map.has_key?(flag_data, &1))
+      ObanHelpers.perform_all()
+
+      Swoosh.TestAssertions.assert_email_sent(
+        to: {admin.name, admin.email},
+        html_body: ~r/#{note.data["object"]}/i
+      )
+    end
   end
 
   describe "GET /users/:nickname/outbox" do
index 3eeb0f7358e9df94baf422a9bbc12ee09a2676fc..6cc25dd9e73a7561dca9e6df28e0be12db97cd72 100644 (file)
@@ -1298,6 +1298,31 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       assert_called(Utils.maybe_federate(%{activity | data: new_data}))
     end
+
+    test_with_mock "reverts on error",
+                   %{
+                     reporter: reporter,
+                     context: context,
+                     target_account: target_account,
+                     reported_activity: reported_activity,
+                     content: content
+                   },
+                   Utils,
+                   [:passthrough],
+                   maybe_federate: fn _ -> {:error, :reverted} end do
+      assert {:error, :reverted} =
+               ActivityPub.flag(%{
+                 actor: reporter,
+                 context: context,
+                 account: target_account,
+                 statuses: [reported_activity],
+                 content: content
+               })
+
+      assert Repo.aggregate(Activity, :count, :id) == 1
+      assert Repo.aggregate(Object, :count, :id) == 2
+      assert Repo.aggregate(Notification, :count, :id) == 0
+    end
   end
 
   test "fetch_activities/2 returns activities addressed to a list " do
index 1710c4d2ae98e975bd17aebf9fdafaa985732315..84362ce78520ea5c7a8b8c82a352a34e175b8c7d 100644 (file)
@@ -3,10 +3,10 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
-  use Pleroma.DataCase
+  use ExUnit.Case
+  use Pleroma.Tests.Helpers
 
   alias Pleroma.HTTP
-  alias Pleroma.Tests.ObanHelpers
   alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy
 
   import Mock
@@ -25,13 +25,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
   setup do: clear_config([:media_proxy, :enabled], true)
 
   test "it prefetches media proxy URIs" do
+    Tesla.Mock.mock(fn %{method: :get, url: "http://example.com/image.jpg"} ->
+      {:ok, %Tesla.Env{status: 200, body: ""}}
+    end)
+
     with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
       MediaProxyWarmingPolicy.filter(@message)
 
-      ObanHelpers.perform_all()
-      # Performing jobs which has been just enqueued
-      ObanHelpers.perform_all()
-
       assert called(HTTP.get(:_, :_, :_))
     end
   end
index 92a116c659e337fceed074396ed1476af6c7494b..9bc58640c7901c8e584ebaedba643cbeca6cdf2a 100644 (file)
@@ -203,6 +203,7 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
       assert count == 1
     end
 
+    # Note: as in Mastodon, `is_discoverable` doesn't anyhow relate to user searchability
     test "it returns non-discoverable users" do
       insert(:user)
       insert(:user, is_discoverable: false)
index 44e63eb80c6dae1ecbe0c2191b086228b2f0f9b1..30d542dfa8876fa55ef45d3b83d2c9cd2413fb24 100644 (file)
@@ -328,7 +328,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
     end
 
     test "posting a status with OGP link preview", %{conn: conn} do
-      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
       clear_config([:rich_media, :enabled], true)
 
       conn =
@@ -1197,7 +1197,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
     end
 
     test "returns rich-media card", %{conn: conn, user: user} do
-      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
 
       {:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp"})
 
@@ -1242,7 +1242,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
     end
 
     test "replaces missing description with an empty string", %{conn: conn, user: user} do
-      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
 
       {:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp-missing-data"})
 
index 282d132c8104a672f52087fb52316d24c91de170..52399fdc80334de928f4b78396cd4c223f23ed5b 100644 (file)
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.Metadata.Providers.RestrictIndexingTest do
              }) == []
     end
 
-    test "for local user when discoverable is false" do
+    test "for local user when `is_discoverable` is false" do
       assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{
                user: %Pleroma.User{local: true, is_discoverable: false}
              }) == [{:meta, [name: "robots", content: "noindex, noarchive"], []}]
diff --git a/test/pleroma/web/metadata_test.exs b/test/pleroma/web/metadata_test.exs
deleted file mode 100644 (file)
index 8fb9465..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.MetadataTest do
-  use Pleroma.DataCase, async: true
-
-  import Pleroma.Factory
-
-  describe "restrict indexing remote users" do
-    test "for remote user" do
-      user = insert(:user, local: false)
-
-      assert Pleroma.Web.Metadata.build_tags(%{user: user}) =~
-               "<meta content=\"noindex, noarchive\" name=\"robots\">"
-    end
-
-    test "for local user" do
-      user = insert(:user, is_discoverable: false)
-
-      assert Pleroma.Web.Metadata.build_tags(%{user: user}) =~
-               "<meta content=\"noindex, noarchive\" name=\"robots\">"
-    end
-
-    test "for local user set to discoverable" do
-      user = insert(:user, is_discoverable: true)
-
-      refute Pleroma.Web.Metadata.build_tags(%{user: user}) =~
-               "<meta content=\"noindex, noarchive\" name=\"robots\">"
-    end
-  end
-
-  describe "no metadata for private instances" do
-    test "for local user set to discoverable" do
-      clear_config([:instance, :public], false)
-      user = insert(:user, bio: "This is my secret fedi account bio", is_discoverable: true)
-
-      assert "" = Pleroma.Web.Metadata.build_tags(%{user: user})
-    end
-
-    test "search exclusion metadata is included" do
-      clear_config([:instance, :public], false)
-      user = insert(:user, bio: "This is my secret fedi account bio", is_discoverable: false)
-
-      assert ~s(<meta content="noindex, noarchive" name="robots">) ==
-               Pleroma.Web.Metadata.build_tags(%{user: user})
-    end
-  end
-end
index ae825787083603217fe6a3deea8e17892cfa0fca..93eef00a2c550b4c045545916d0568218f02d004 100644 (file)
@@ -48,7 +48,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
 
     clear_config([:rich_media, :enabled], true)
 
-    Tesla.Mock.mock(fn
+    Tesla.Mock.mock_global(fn
       %{url: "https://example.com/ogp"} ->
         %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}
     end)
index 80b882ee413d5b4a6de7f7dcf3723428eacac4ec..8eb07dc3c19e4f54d24f5372a8a46a58147a29d3 100644 (file)
@@ -24,7 +24,7 @@ defmodule Pleroma.Factory do
     }
   end
 
-  def user_factory do
+  def user_factory(attrs \\ %{}) do
     user = %User{
       name: sequence(:name, &"Test テスト User #{&1}"),
       email: sequence(:email, &"user#{&1}@example.com"),
@@ -39,13 +39,29 @@ defmodule Pleroma.Factory do
       ap_enabled: true
     }
 
-    %{
-      user
-      | ap_id: User.ap_id(user),
-        follower_address: User.ap_followers(user),
-        following_address: User.ap_following(user),
-        raw_bio: user.bio
-    }
+    urls =
+      if attrs[:local] == false do
+        base_domain = Enum.random(["domain1.com", "domain2.com", "domain3.com"])
+
+        ap_id = "https://#{base_domain}/users/#{user.nickname}"
+
+        %{
+          ap_id: ap_id,
+          follower_address: ap_id <> "/followers",
+          following_address: ap_id <> "/following"
+        }
+      else
+        %{
+          ap_id: User.ap_id(user),
+          follower_address: User.ap_followers(user),
+          following_address: User.ap_following(user)
+        }
+      end
+
+    user
+    |> Map.put(:raw_bio, user.bio)
+    |> Map.merge(urls)
+    |> merge_attributes(attrs)
   end
 
   def user_relationship_factory(attrs \\ %{}) do