From 23d279e03ee1f7a1285614754738711359bc4b81 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Thu, 1 Aug 2019 17:28:00 +0300 Subject: [PATCH 001/272] [#1149] Replaced RetryQueue with oban-based retries. --- config/config.exs | 17 +- config/test.exs | 4 + docs/config.md | 7 - lib/pleroma/application.ex | 4 +- lib/pleroma/web/activity_pub/publisher.ex | 16 +- lib/pleroma/web/federator/federator.ex | 14 - lib/pleroma/web/federator/publisher.ex | 22 +- lib/pleroma/web/federator/retry_queue.ex | 239 ------------------ lib/pleroma/web/salmon/salmon.ex | 11 +- lib/pleroma/workers/publisher.ex | 14 + mix.exs | 1 + mix.lock | 1 + .../20190730055101_add_oban_jobs_table.exs | 6 + test/user_test.exs | 15 +- test/web/activity_pub/publisher_test.exs | 2 +- test/web/federator_test.exs | 78 +++--- test/web/retry_queue_test.exs | 48 ---- test/web/salmon/salmon_test.exs | 2 +- 18 files changed, 106 insertions(+), 395 deletions(-) delete mode 100644 lib/pleroma/web/federator/retry_queue.ex create mode 100644 lib/pleroma/workers/publisher.ex create mode 100644 priv/repo/migrations/20190730055101_add_oban_jobs_table.exs delete mode 100644 test/web/retry_queue_test.exs diff --git a/config/config.exs b/config/config.exs index 17770640a..1bb325bf5 100644 --- a/config/config.exs +++ b/config/config.exs @@ -440,13 +440,7 @@ "web" ] -config :pleroma, Pleroma.Web.Federator.RetryQueue, - enabled: false, - max_jobs: 20, - initial_timeout: 30, - max_retries: 5 - -config :pleroma_job_queue, :queues, +job_queues = [ federator_incoming: 50, federator_outgoing: 50, web_push: 50, @@ -454,6 +448,15 @@ transmogrifier: 20, scheduled_activities: 10, background: 5 +] + +config :pleroma_job_queue, :queues, job_queues + +config :pleroma, Oban, + repo: Pleroma.Repo, + verbose: false, + prune: {:maxage, 60 * 60 * 24 * 7}, + queues: job_queues config :pleroma, :fetch_initial_posts, enabled: false, diff --git a/config/test.exs b/config/test.exs index 92dca18bc..23d9bf779 100644 --- a/config/test.exs +++ b/config/test.exs @@ -62,6 +62,10 @@ config :pleroma_job_queue, disabled: true +config :pleroma, Oban, + queues: false, + prune: :disabled + config :pleroma, Pleroma.ScheduledActivity, daily_user_limit: 2, total_user_limit: 3, diff --git a/docs/config.md b/docs/config.md index 02f86dc16..5c18ffdbf 100644 --- a/docs/config.md +++ b/docs/config.md @@ -412,13 +412,6 @@ config :pleroma_job_queue, :queues, This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the `max_jobs` set to `50`. -## Pleroma.Web.Federator.RetryQueue - -* `enabled`: If set to `true`, failed federation jobs will be retried -* `max_jobs`: The maximum amount of parallel federation jobs running at the same time. -* `initial_timeout`: The initial timeout in seconds -* `max_retries`: The maximum number of times a federation job is retried - ## Pleroma.Web.Metadata * `providers`: a list of metadata providers to enable. Providers available: * Pleroma.Web.Metadata.Providers.OpenGraph diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 035331491..ce7d8c4b2 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -120,8 +120,8 @@ def start(_type, _args) do hackney_pool_children() ++ [ %{ - id: Pleroma.Web.Federator.RetryQueue, - start: {Pleroma.Web.Federator.RetryQueue, :start_link, []} + id: Oban, + start: {Oban, :start_link, [Application.get_env(:pleroma, Oban)]} }, %{ id: Pleroma.Web.OAuth.Token.CleanWorker, diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 46edab0bd..29f3221d1 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -85,6 +85,15 @@ def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = pa end end + def publish_one(%{actor_id: actor_id} = params) do + actor = User.get_by_id(actor_id) + + params + |> Map.delete(:actor_id) + |> Map.put(:actor, actor) + |> publish_one() + end + defp should_federate?(inbox, public) do if public do true @@ -160,7 +169,8 @@ def determine_inbox( Publishes an activity with BCC to all relevant peers. """ - def publish(actor, %{data: %{"bcc" => bcc}} = activity) when is_list(bcc) and bcc != [] do + def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity) + when is_list(bcc) and bcc != [] do public = is_public?(activity) {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) @@ -187,7 +197,7 @@ def publish(actor, %{data: %{"bcc" => bcc}} = activity) when is_list(bcc) and bc Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{ inbox: inbox, json: json, - actor: actor, + actor_id: actor.id, id: activity.data["id"], unreachable_since: unreachable_since }) @@ -222,7 +232,7 @@ def publish(%User{} = actor, %Activity{} = activity) do %{ inbox: inbox, json: json, - actor: actor, + actor_id: actor.id, id: activity.data["id"], unreachable_since: unreachable_since } diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index f4f9e83e0..97ec9d549 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -10,7 +10,6 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Federator.Publisher - alias Pleroma.Web.Federator.RetryQueue alias Pleroma.Web.OStatus alias Pleroma.Web.Websub @@ -130,19 +129,6 @@ def perform(:incoming_ap_doc, params) do end end - def perform( - :publish_single_websub, - %{xml: _xml, topic: _topic, callback: _callback, secret: _secret} = params - ) do - case Websub.publish_one(params) do - {:ok, _} -> - :ok - - {:error, _} -> - RetryQueue.enqueue(params, Websub) - end - end - def perform(type, _) do Logger.debug(fn -> "Unknown task: #{type}" end) {:error, "Don't know what to do with this"} diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 70f870244..e8c1bf17f 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.Federator.Publisher do alias Pleroma.Activity alias Pleroma.Config alias Pleroma.User - alias Pleroma.Web.Federator.RetryQueue require Logger @@ -30,23 +29,10 @@ defmodule Pleroma.Web.Federator.Publisher do Enqueue publishing a single activity. """ @spec enqueue_one(module(), Map.t()) :: :ok - def enqueue_one(module, %{} = params), - do: PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_one, module, params]) - - @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()} - def perform(:publish_one, module, params) do - case apply(module, :publish_one, [params]) do - {:ok, _} -> - :ok - - {:error, _e} -> - RetryQueue.enqueue(params, module) - end - end - - def perform(type, _, _) do - Logger.debug("Unknown task: #{type}") - {:error, "Don't know what to do with this"} + def enqueue_one(module, %{} = params) do + %{module: to_string(module), params: params} + |> Pleroma.Workers.Publisher.new() + |> Pleroma.Repo.insert() end @doc """ diff --git a/lib/pleroma/web/federator/retry_queue.ex b/lib/pleroma/web/federator/retry_queue.ex deleted file mode 100644 index 3db948c2e..000000000 --- a/lib/pleroma/web/federator/retry_queue.ex +++ /dev/null @@ -1,239 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Federator.RetryQueue do - use GenServer - - require Logger - - def init(args) do - queue_table = :ets.new(:pleroma_retry_queue, [:bag, :protected]) - - {:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}} - end - - def start_link do - enabled = - if Pleroma.Config.get(:env) == :test, - do: true, - else: Pleroma.Config.get([__MODULE__, :enabled], false) - - if enabled do - Logger.info("Starting retry queue") - - linkres = - GenServer.start_link( - __MODULE__, - %{delivered: 0, dropped: 0, queue_table: nil, running_jobs: nil}, - name: __MODULE__ - ) - - maybe_kickoff_timer() - linkres - else - Logger.info("Retry queue disabled") - :ignore - end - end - - def enqueue(data, transport, retries \\ 0) do - GenServer.cast(__MODULE__, {:maybe_enqueue, data, transport, retries + 1}) - end - - def get_stats do - GenServer.call(__MODULE__, :get_stats) - end - - def reset_stats do - GenServer.call(__MODULE__, :reset_stats) - end - - def get_retry_params(retries) do - if retries > Pleroma.Config.get([__MODULE__, :max_retries]) do - {:drop, "Max retries reached"} - else - {:retry, growth_function(retries)} - end - end - - def get_retry_timer_interval do - Pleroma.Config.get([:retry_queue, :interval], 1000) - end - - defp ets_count_expires(table, current_time) do - :ets.select_count( - table, - [ - { - {:"$1", :"$2"}, - [{:"=<", :"$1", {:const, current_time}}], - [true] - } - ] - ) - end - - defp ets_pop_n_expired(table, current_time, desired) do - {popped, _continuation} = - :ets.select( - table, - [ - { - {:"$1", :"$2"}, - [{:"=<", :"$1", {:const, current_time}}], - [:"$_"] - } - ], - desired - ) - - popped - |> Enum.each(fn e -> - :ets.delete_object(table, e) - end) - - popped - end - - def maybe_start_job(running_jobs, queue_table) do - # we don't want to hit the ets or the DateTime more times than we have to - # could optimize slightly further by not using the count, and instead grabbing - # up to N objects early... - current_time = DateTime.to_unix(DateTime.utc_now()) - n_running_jobs = :sets.size(running_jobs) - - if n_running_jobs < Pleroma.Config.get([__MODULE__, :max_jobs]) do - n_ready_jobs = ets_count_expires(queue_table, current_time) - - if n_ready_jobs > 0 do - # figure out how many we could start - available_job_slots = Pleroma.Config.get([__MODULE__, :max_jobs]) - n_running_jobs - start_n_jobs(running_jobs, queue_table, current_time, available_job_slots) - else - running_jobs - end - else - running_jobs - end - end - - defp start_n_jobs(running_jobs, _queue_table, _current_time, 0) do - running_jobs - end - - defp start_n_jobs(running_jobs, queue_table, current_time, available_job_slots) - when available_job_slots > 0 do - candidates = ets_pop_n_expired(queue_table, current_time, available_job_slots) - - candidates - |> List.foldl(running_jobs, fn {_, e}, rj -> - {:ok, pid} = Task.start(fn -> worker(e) end) - mref = Process.monitor(pid) - :sets.add_element(mref, rj) - end) - end - - def worker({:send, data, transport, retries}) do - case transport.publish_one(data) do - {:ok, _} -> - GenServer.cast(__MODULE__, :inc_delivered) - :delivered - - {:error, _reason} -> - enqueue(data, transport, retries) - :retry - end - end - - def handle_call(:get_stats, _from, %{delivered: delivery_count, dropped: drop_count} = state) do - {:reply, %{delivered: delivery_count, dropped: drop_count}, state} - end - - def handle_call(:reset_stats, _from, %{delivered: delivery_count, dropped: drop_count} = state) do - {:reply, %{delivered: delivery_count, dropped: drop_count}, - %{state | delivered: 0, dropped: 0}} - end - - def handle_cast(:reset_stats, state) do - {:noreply, %{state | delivered: 0, dropped: 0}} - end - - def handle_cast( - {:maybe_enqueue, data, transport, retries}, - %{dropped: drop_count, queue_table: queue_table, running_jobs: running_jobs} = state - ) do - case get_retry_params(retries) do - {:retry, timeout} -> - :ets.insert(queue_table, {timeout, {:send, data, transport, retries}}) - running_jobs = maybe_start_job(running_jobs, queue_table) - {:noreply, %{state | running_jobs: running_jobs}} - - {:drop, message} -> - Logger.debug(message) - {:noreply, %{state | dropped: drop_count + 1}} - end - end - - def handle_cast(:kickoff_timer, state) do - retry_interval = get_retry_timer_interval() - Process.send_after(__MODULE__, :retry_timer_run, retry_interval) - {:noreply, state} - end - - def handle_cast(:inc_delivered, %{delivered: delivery_count} = state) do - {:noreply, %{state | delivered: delivery_count + 1}} - end - - def handle_cast(:inc_dropped, %{dropped: drop_count} = state) do - {:noreply, %{state | dropped: drop_count + 1}} - end - - def handle_info({:send, data, transport, retries}, %{delivered: delivery_count} = state) do - case transport.publish_one(data) do - {:ok, _} -> - {:noreply, %{state | delivered: delivery_count + 1}} - - {:error, _reason} -> - enqueue(data, transport, retries) - {:noreply, state} - end - end - - def handle_info( - :retry_timer_run, - %{queue_table: queue_table, running_jobs: running_jobs} = state - ) do - maybe_kickoff_timer() - running_jobs = maybe_start_job(running_jobs, queue_table) - {:noreply, %{state | running_jobs: running_jobs}} - end - - def handle_info({:DOWN, ref, :process, _pid, _reason}, state) do - %{running_jobs: running_jobs, queue_table: queue_table} = state - running_jobs = :sets.del_element(ref, running_jobs) - running_jobs = maybe_start_job(running_jobs, queue_table) - {:noreply, %{state | running_jobs: running_jobs}} - end - - def handle_info(unknown, state) do - Logger.debug("RetryQueue: don't know what to do with #{inspect(unknown)}, ignoring") - {:noreply, state} - end - - if Pleroma.Config.get(:env) == :test do - defp growth_function(_retries) do - _shutit = Pleroma.Config.get([__MODULE__, :initial_timeout]) - DateTime.to_unix(DateTime.utc_now()) - 1 - end - else - defp growth_function(retries) do - round(Pleroma.Config.get([__MODULE__, :initial_timeout]) * :math.pow(retries, 3)) + - DateTime.to_unix(DateTime.utc_now()) - end - end - - defp maybe_kickoff_timer do - GenServer.cast(__MODULE__, :kickoff_timer) - end -end diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 9b01ebcc6..bbaa293fd 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -170,6 +170,15 @@ def publish_one(%{recipient: url, feed: feed} = params) when is_binary(url) do end end + def publish_one(%{recipient_id: recipient_id} = params) do + recipient = User.get_by_id(recipient_id) + + params + |> Map.delete(:recipient_id) + |> Map.put(:recipient, recipient) + |> publish_one() + end + def publish_one(_), do: :noop @supported_activities [ @@ -218,7 +227,7 @@ def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end) Publisher.enqueue_one(__MODULE__, %{ - recipient: remote_user, + recipient_id: remote_user.id, feed: feed, unreachable_since: reachable_urls_metadata[remote_user.info.salmon] }) diff --git a/lib/pleroma/workers/publisher.ex b/lib/pleroma/workers/publisher.ex new file mode 100644 index 000000000..639794830 --- /dev/null +++ b/lib/pleroma/workers/publisher.ex @@ -0,0 +1,14 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Publisher do + use Oban.Worker, queue: "federator_outgoing", max_attempts: 5 + + @impl Oban.Worker + def perform(%Oban.Job{args: %{module: module_name, params: params}}) do + module_name + |> String.to_atom() + |> apply(:publish_one, [params]) + end +end diff --git a/mix.exs b/mix.exs index 2a8fe2e9d..1ca7a4a77 100644 --- a/mix.exs +++ b/mix.exs @@ -101,6 +101,7 @@ defp deps do {:phoenix_ecto, "~> 4.0"}, {:ecto_sql, "~> 3.1"}, {:postgrex, ">= 0.13.5"}, + {:oban, "~> 0.6"}, {:gettext, "~> 0.15"}, {:comeonin, "~> 4.1.1"}, {:pbkdf2_elixir, "~> 0.12.3"}, diff --git a/mix.lock b/mix.lock index 65da7be8b..8c0b9734e 100644 --- a/mix.lock +++ b/mix.lock @@ -55,6 +55,7 @@ "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"}, + "oban": {:hex, :oban, "0.6.0", "8b9b861355610e703e58a878bc29959f3f0e1b4cd1e90d785cf2bb2498d3b893", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"}, "phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/priv/repo/migrations/20190730055101_add_oban_jobs_table.exs b/priv/repo/migrations/20190730055101_add_oban_jobs_table.exs new file mode 100644 index 000000000..2f201bd05 --- /dev/null +++ b/priv/repo/migrations/20190730055101_add_oban_jobs_table.exs @@ -0,0 +1,6 @@ +defmodule Pleroma.Repo.Migrations.AddObanJobsTable do + use Ecto.Migration + + defdelegate up, to: Oban.Migrations + defdelegate down, to: Oban.Migrations +end diff --git a/test/user_test.exs b/test/user_test.exs index 556df45fd..70c376384 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -12,9 +12,9 @@ defmodule Pleroma.UserTest do alias Pleroma.Web.CommonAPI use Pleroma.DataCase + use Oban.Testing, repo: Pleroma.Repo import Pleroma.Factory - import Mock setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -1034,11 +1034,7 @@ test "it deletes a user, all follow relationships and all activities", %{user: u refute Activity.get_by_id(repeat.id) end - test_with_mock "it sends out User Delete activity", - %{user: user}, - Pleroma.Web.ActivityPub.Publisher, - [:passthrough], - [] do + test "it sends out User Delete activity", %{user: user} do config_path = [:instance, :federating] initial_setting = Pleroma.Config.get(config_path) Pleroma.Config.put(config_path, true) @@ -1048,11 +1044,8 @@ test "it deletes a user, all follow relationships and all activities", %{user: u {:ok, _user} = User.delete(user) - assert called( - Pleroma.Web.ActivityPub.Publisher.publish_one(%{ - inbox: "http://mastodon.example.org/inbox" - }) - ) + assert [%{args: %{"params" => %{"inbox" => "http://mastodon.example.org/inbox"}}}] = + all_enqueued(worker: Pleroma.Workers.Publisher) Pleroma.Config.put(config_path, initial_setting) end diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index 36a39c84c..26d019878 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -257,7 +257,7 @@ test "it returns inbox for messages involving single recipients in total" do assert called( Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ inbox: "https://domain.com/users/nick1/inbox", - actor: actor, + actor_id: actor.id, id: note_activity.data["id"] }) ) diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 6e143eee4..5c1704548 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -6,7 +6,10 @@ defmodule Pleroma.Web.FederatorTest do alias Pleroma.Instances alias Pleroma.Web.CommonAPI alias Pleroma.Web.Federator + use Pleroma.DataCase + use Oban.Testing, repo: Pleroma.Repo + import Pleroma.Factory import Mock @@ -22,15 +25,6 @@ defmodule Pleroma.Web.FederatorTest do :ok end - describe "Publisher.perform" do - test "call `perform` with unknown task" do - assert { - :error, - "Don't know what to do with this" - } = Pleroma.Web.Federator.Publisher.perform("test", :ok, :ok) - end - end - describe "Publish an activity" do setup do user = insert(:user) @@ -73,10 +67,7 @@ test "with relays deactivated, it does not publish to the relay", %{ end describe "Targets reachability filtering in `publish`" do - test_with_mock "it federates only to reachable instances via AP", - Pleroma.Web.ActivityPub.Publisher, - [:passthrough], - [] do + test "it federates only to reachable instances via AP" do user = insert(:user) {inbox1, inbox2} = @@ -104,20 +95,13 @@ test "with relays deactivated, it does not publish to the relay", %{ {:ok, _activity} = CommonAPI.post(user, %{"status" => "HI @nick1@domain.com, @nick2@domain2.com!"}) - assert called( - Pleroma.Web.ActivityPub.Publisher.publish_one(%{ - inbox: inbox1, - unreachable_since: dt - }) - ) + expected_dt = NaiveDateTime.to_iso8601(dt) - refute called(Pleroma.Web.ActivityPub.Publisher.publish_one(%{inbox: inbox2})) + assert [%{args: %{"params" => %{"inbox" => ^inbox1, "unreachable_since" => ^expected_dt}}}] = + all_enqueued(worker: Pleroma.Workers.Publisher) end - test_with_mock "it federates only to reachable instances via Websub", - Pleroma.Web.Websub, - [:passthrough], - [] do + test "it federates only to reachable instances via Websub" do user = insert(:user) websub_topic = Pleroma.Web.OStatus.feed_path(user) @@ -142,23 +126,25 @@ test "with relays deactivated, it does not publish to the relay", %{ {:ok, _activity} = CommonAPI.post(user, %{"status" => "HI"}) - assert called( - Pleroma.Web.Websub.publish_one(%{ - callback: sub2.callback, - unreachable_since: dt - }) - ) + expected_callback = sub2.callback + expected_dt = NaiveDateTime.to_iso8601(dt) - refute called(Pleroma.Web.Websub.publish_one(%{callback: sub1.callback})) + assert [ + %{ + args: %{ + "params" => %{ + "callback" => ^expected_callback, + "unreachable_since" => ^expected_dt + } + } + } + ] = all_enqueued(worker: Pleroma.Workers.Publisher) end - test_with_mock "it federates only to reachable instances via Salmon", - Pleroma.Web.Salmon, - [:passthrough], - [] do + test "it federates only to reachable instances via Salmon" do user = insert(:user) - remote_user1 = + _remote_user1 = insert(:user, %{ local: false, nickname: "nick1@domain.com", @@ -174,6 +160,8 @@ test "with relays deactivated, it does not publish to the relay", %{ info: %{salmon: "https://domain2.com/salmon"} }) + remote_user2_id = remote_user2.id + dt = NaiveDateTime.utc_now() Instances.set_unreachable(remote_user2.ap_id, dt) @@ -182,14 +170,18 @@ test "with relays deactivated, it does not publish to the relay", %{ {:ok, _activity} = CommonAPI.post(user, %{"status" => "HI @nick1@domain.com, @nick2@domain2.com!"}) - assert called( - Pleroma.Web.Salmon.publish_one(%{ - recipient: remote_user2, - unreachable_since: dt - }) - ) + expected_dt = NaiveDateTime.to_iso8601(dt) - refute called(Pleroma.Web.Salmon.publish_one(%{recipient: remote_user1})) + assert [ + %{ + args: %{ + "params" => %{ + "recipient_id" => ^remote_user2_id, + "unreachable_since" => ^expected_dt + } + } + } + ] = all_enqueued(worker: Pleroma.Workers.Publisher) end end diff --git a/test/web/retry_queue_test.exs b/test/web/retry_queue_test.exs deleted file mode 100644 index ecb3ce5d0..000000000 --- a/test/web/retry_queue_test.exs +++ /dev/null @@ -1,48 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule MockActivityPub do - def publish_one({ret, waiter}) do - send(waiter, :complete) - {ret, "success"} - end -end - -defmodule Pleroma.Web.Federator.RetryQueueTest do - use Pleroma.DataCase - alias Pleroma.Web.Federator.RetryQueue - - @small_retry_count 0 - @hopeless_retry_count 10 - - setup do - RetryQueue.reset_stats() - end - - test "RetryQueue responds to stats request" do - assert %{delivered: 0, dropped: 0} == RetryQueue.get_stats() - end - - test "failed posts are retried" do - {:retry, _timeout} = RetryQueue.get_retry_params(@small_retry_count) - - wait_task = - Task.async(fn -> - receive do - :complete -> :ok - end - end) - - RetryQueue.enqueue({:ok, wait_task.pid}, MockActivityPub, @small_retry_count) - Task.await(wait_task) - assert %{delivered: 1, dropped: 0} == RetryQueue.get_stats() - end - - test "posts that have been tried too many times are dropped" do - {:drop, _timeout} = RetryQueue.get_retry_params(@hopeless_retry_count) - - RetryQueue.enqueue({:ok, nil}, MockActivityPub, @hopeless_retry_count) - assert %{delivered: 0, dropped: 1} == RetryQueue.get_stats() - end -end diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs index e86e76fe9..0186f3fef 100644 --- a/test/web/salmon/salmon_test.exs +++ b/test/web/salmon/salmon_test.exs @@ -96,6 +96,6 @@ test "it gets a magic key" do Salmon.publish(user, activity) - assert called(Publisher.enqueue_one(Salmon, %{recipient: mentioned_user})) + assert called(Publisher.enqueue_one(Salmon, %{recipient_id: mentioned_user.id})) end end From b7fad8d395c2bd1afe445a370e539571f5ec0c18 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 9 Aug 2019 20:08:01 +0300 Subject: [PATCH 002/272] [#1149] Oban jobs implementation for :federator_incoming and :federator_outgoing queues. --- config/config.exs | 7 + lib/pleroma/web/activity_pub/utils.ex | 9 +- lib/pleroma/web/federator/federator.ex | 134 +++++------------- lib/pleroma/web/federator/publisher.ex | 12 +- lib/pleroma/workers/publisher.ex | 25 +++- lib/pleroma/workers/receiver.ex | 61 ++++++++ lib/pleroma/workers/subscriber.ex | 44 ++++++ test/activity_test.exs | 4 +- test/support/oban_helpers.ex | 36 +++++ test/user_test.exs | 11 +- .../activity_pub_controller_test.exs | 14 +- test/web/federator_test.exs | 57 +++++--- test/web/websub/websub_test.exs | 4 + 13 files changed, 280 insertions(+), 138 deletions(-) create mode 100644 lib/pleroma/workers/receiver.ex create mode 100644 lib/pleroma/workers/subscriber.ex create mode 100644 test/support/oban_helpers.ex diff --git a/config/config.exs b/config/config.exs index 1bb325bf5..5fd64365c 100644 --- a/config/config.exs +++ b/config/config.exs @@ -458,6 +458,13 @@ prune: {:maxage, 60 * 60 * 24 * 7}, queues: job_queues +config :pleroma, :workers, + retries: [ + compile_time_default: 1, + federator_incoming: 5, + federator_outgoing: 5 + ] + config :pleroma, :fetch_initial_posts, enabled: false, pages: 5 diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 39074888b..f0917f9d4 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -168,14 +168,7 @@ def create_context(context) do """ def maybe_federate(%Activity{local: true} = activity) do if Pleroma.Config.get!([:instance, :federating]) do - priority = - case activity.data["type"] do - "Delete" -> 10 - "Create" -> 1 - _ -> 5 - end - - Pleroma.Web.Federator.publish(activity, priority) + Pleroma.Web.Federator.publish(activity) end :ok diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 97ec9d549..bb9eadfee 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -3,22 +3,15 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Federator do - alias Pleroma.Activity - alias Pleroma.Object.Containment - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.Federator.Publisher - alias Pleroma.Web.OStatus - alias Pleroma.Web.Websub + alias Pleroma.Workers.Publisher, as: PublisherWorker + alias Pleroma.Workers.Receiver, as: ReceiverWorker + alias Pleroma.Workers.Subscriber, as: SubscriberWorker require Logger def init do # 1 minute - Process.sleep(1000 * 60) - refresh_subscriptions() + refresh_subscriptions(schedule_in: 60) end @doc "Addresses [memory leaks on recursive replies fetching](https://git.pleroma.social/pleroma/pleroma/issues/161)" @@ -36,111 +29,50 @@ def allowed_incoming_reply_depth?(depth) do # Client API def incoming_doc(doc) do - PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc]) + %{"op" => "incoming_doc", "body" => doc} + |> ReceiverWorker.new(worker_args(:federator_incoming)) + |> Pleroma.Repo.insert() end def incoming_ap_doc(params) do - PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params]) + %{"op" => "incoming_ap_doc", "params" => params} + |> ReceiverWorker.new(worker_args(:federator_incoming)) + |> Pleroma.Repo.insert() end - def publish(activity, priority \\ 1) do - PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority) + def publish(%{id: "pleroma:fakeid"} = activity) do + PublisherWorker.perform_publish(activity) + end + + def publish(activity) do + %{"op" => "publish", "activity_id" => activity.id} + |> PublisherWorker.new(worker_args(:federator_outgoing)) + |> Pleroma.Repo.insert() end def verify_websub(websub) do - PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub]) + %{"op" => "verify_websub", "websub_id" => websub.id} + |> SubscriberWorker.new(worker_args(:federator_outgoing)) + |> Pleroma.Repo.insert() end - def request_subscription(sub) do - PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub]) + def request_subscription(websub) do + %{"op" => "request_subscription", "websub_id" => websub.id} + |> SubscriberWorker.new(worker_args(:federator_outgoing)) + |> Pleroma.Repo.insert() end - def refresh_subscriptions do - PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions]) + def refresh_subscriptions(worker_args \\ []) do + %{"op" => "refresh_subscriptions"} + |> SubscriberWorker.new(worker_args ++ [max_attempts: 1] ++ worker_args(:federator_outgoing)) + |> Pleroma.Repo.insert() end - # Job Worker Callbacks - - def perform(:refresh_subscriptions) do - Logger.debug("Federator running refresh subscriptions") - Websub.refresh_subscriptions() - - spawn(fn -> - # 6 hours - Process.sleep(1000 * 60 * 60 * 6) - refresh_subscriptions() - end) - end - - def perform(:request_subscription, websub) do - Logger.debug("Refreshing #{websub.topic}") - - with {:ok, websub} <- Websub.request_subscription(websub) do - Logger.debug("Successfully refreshed #{websub.topic}") + defp worker_args(queue) do + if max_attempts = Pleroma.Config.get([:workers, :retries, queue]) do + [max_attempts: max_attempts] else - _e -> Logger.debug("Couldn't refresh #{websub.topic}") - end - end - - def perform(:publish, activity) do - Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end) - - with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]), - {:ok, actor} <- User.ensure_keys_present(actor) do - Publisher.publish(actor, activity) - end - end - - def perform(:verify_websub, websub) do - Logger.debug(fn -> - "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})" - end) - - Websub.verify(websub) - end - - def perform(:incoming_doc, doc) do - Logger.info("Got document, trying to parse") - OStatus.handle_incoming(doc) - end - - def perform(:incoming_ap_doc, params) do - Logger.info("Handling incoming AP activity") - - params = Utils.normalize_params(params) - - # NOTE: we use the actor ID to do the containment, this is fine because an - # 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, activity} <- Transmogrifier.handle_incoming(params) do - {:ok, activity} - else - %Activity{} -> - Logger.info("Already had #{params["id"]}") - :error - - _e -> - # Just drop those for now - Logger.info("Unhandled activity") - Logger.info(Jason.encode!(params, pretty: true)) - :error - end - end - - def perform(type, _) do - Logger.debug(fn -> "Unknown task: #{type}" end) - {:error, "Don't know what to do with this"} - end - - def ap_enabled_actor(id) do - user = User.get_cached_by_ap_id(id) - - if User.ap_enabled?(user) do - {:ok, user} - else - ActivityPub.make_user_from_ap_id(id) + [] end end end diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index e8c1bf17f..05d2be615 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.Federator.Publisher do alias Pleroma.Activity alias Pleroma.Config alias Pleroma.User + alias Pleroma.Workers.Publisher, as: PublisherWorker require Logger @@ -30,8 +31,15 @@ defmodule Pleroma.Web.Federator.Publisher do """ @spec enqueue_one(module(), Map.t()) :: :ok def enqueue_one(module, %{} = params) do - %{module: to_string(module), params: params} - |> Pleroma.Workers.Publisher.new() + worker_args = + if max_attempts = Pleroma.Config.get([:workers, :retries, :federator_outgoing]) do + [max_attempts: max_attempts] + else + [] + end + + %{"op" => "publish_one", "module" => to_string(module), "params" => params} + |> PublisherWorker.new(worker_args) |> Pleroma.Repo.insert() end diff --git a/lib/pleroma/workers/publisher.ex b/lib/pleroma/workers/publisher.ex index 639794830..67871977a 100644 --- a/lib/pleroma/workers/publisher.ex +++ b/lib/pleroma/workers/publisher.ex @@ -3,12 +3,33 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.Publisher do - use Oban.Worker, queue: "federator_outgoing", max_attempts: 5 + alias Pleroma.Activity + alias Pleroma.User + + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "federator_outgoing", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) @impl Oban.Worker - def perform(%Oban.Job{args: %{module: module_name, params: params}}) do + def perform(%{"op" => "publish", "activity_id" => activity_id}) do + with %Activity{} = activity <- Activity.get_by_id(activity_id) do + perform_publish(activity) + else + _ -> raise "Non-existing activity: #{activity_id}" + end + end + + def perform(%{"op" => "publish_one", "module" => module_name, "params" => params}) do module_name |> String.to_atom() |> apply(:publish_one, [params]) end + + def perform_publish(%Activity{} = activity) do + with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]), + {:ok, actor} <- User.ensure_keys_present(actor) do + Pleroma.Web.Federator.Publisher.publish(actor, activity) + end + end end diff --git a/lib/pleroma/workers/receiver.ex b/lib/pleroma/workers/receiver.ex new file mode 100644 index 000000000..43558b4e6 --- /dev/null +++ b/lib/pleroma/workers/receiver.ex @@ -0,0 +1,61 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Receiver do + alias Pleroma.Activity + alias Pleroma.Object.Containment + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.OStatus + + require Logger + + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "federator_incoming", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + + @impl Oban.Worker + def perform(%{"op" => "incoming_doc", "body" => doc}) do + Logger.info("Got incoming document, trying to parse") + OStatus.handle_incoming(doc) + end + + def perform(%{"op" => "incoming_ap_doc", "params" => params}) do + Logger.info("Handling incoming AP activity") + + params = Utils.normalize_params(params) + + # NOTE: we use the actor ID to do the containment, this is fine because an + # 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, activity} <- Transmogrifier.handle_incoming(params) do + {:ok, activity} + else + %Activity{} -> + Logger.info("Already had #{params["id"]}") + :error + + _e -> + # Just drop those for now + Logger.info("Unhandled activity") + Logger.info(Jason.encode!(params, pretty: true)) + :error + end + end + + defp ap_enabled_actor(id) do + user = User.get_cached_by_ap_id(id) + + if User.ap_enabled?(user) do + {:ok, user} + else + ActivityPub.make_user_from_ap_id(id) + end + end +end diff --git a/lib/pleroma/workers/subscriber.ex b/lib/pleroma/workers/subscriber.ex new file mode 100644 index 000000000..a8c01bb10 --- /dev/null +++ b/lib/pleroma/workers/subscriber.ex @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Subscriber do + alias Pleroma.Repo + alias Pleroma.Web.Websub + alias Pleroma.Web.Websub.WebsubClientSubscription + + require Logger + + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "federator_outgoing", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + + @impl Oban.Worker + def perform(%{"op" => "refresh_subscriptions"}) do + Websub.refresh_subscriptions() + # Schedule the next run in 6 hours + Pleroma.Web.Federator.refresh_subscriptions(schedule_in: 3600 * 6) + end + + def perform(%{"op" => "request_subscription", "websub_id" => websub_id}) do + websub = Repo.get(WebsubClientSubscription, websub_id) + Logger.debug("Refreshing #{websub.topic}") + + with {:ok, websub} <- Websub.request_subscription(websub) do + Logger.debug("Successfully refreshed #{websub.topic}") + else + _e -> Logger.debug("Couldn't refresh #{websub.topic}") + end + end + + def perform(%{"op" => "verify_websub", "websub_id" => websub_id}) do + websub = Repo.get(WebsubClientSubscription, websub_id) + + Logger.debug(fn -> + "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})" + end) + + Websub.verify(websub) + end +end diff --git a/test/activity_test.exs b/test/activity_test.exs index b27f6fd36..b9c12adb2 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.ActivityTest do use Pleroma.DataCase alias Pleroma.Activity alias Pleroma.Bookmark + alias Pleroma.ObanHelpers alias Pleroma.Object alias Pleroma.ThreadMute import Pleroma.Factory @@ -125,7 +126,8 @@ test "when association is not loaded" do } {:ok, local_activity} = Pleroma.Web.CommonAPI.post(user, %{"status" => "find me!"}) - {:ok, remote_activity} = Pleroma.Web.Federator.incoming_ap_doc(params) + {:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params) + {:ok, remote_activity} = ObanHelpers.perform(job) %{local_activity: local_activity, remote_activity: remote_activity, user: user} end diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex new file mode 100644 index 000000000..54b5a9566 --- /dev/null +++ b/test/support/oban_helpers.ex @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ObanHelpers do + @moduledoc """ + Oban test helpers. + """ + + alias Pleroma.Repo + + def perform(%Oban.Job{} = job) do + res = apply(String.to_existing_atom("Elixir." <> job.worker), :perform, [job]) + Repo.delete(job) + res + end + + def perform(jobs) when is_list(jobs) do + for job <- jobs, do: perform(job) + end + + def member?(%{} = job_args, jobs) when is_list(jobs) do + Enum.any?(jobs, fn job -> + member?(job_args, job.args) + end) + end + + def member?(%{} = test_attrs, %{} = attrs) do + Enum.all?( + test_attrs, + fn {k, _v} -> member?(test_attrs[k], attrs[k]) end + ) + end + + def member?(x, y), do: x == y +end diff --git a/test/user_test.exs b/test/user_test.exs index 70c376384..ee6d8e8f3 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.UserTest do alias Pleroma.Activity alias Pleroma.Builders.UserBuilder + alias Pleroma.ObanHelpers alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -1044,8 +1045,16 @@ test "it sends out User Delete activity", %{user: user} do {:ok, _user} = User.delete(user) - assert [%{args: %{"params" => %{"inbox" => "http://mastodon.example.org/inbox"}}}] = + assert ObanHelpers.member?( + %{ + "op" => "publish_one", + "params" => %{ + "inbox" => "http://mastodon.example.org/inbox", + "id" => "pleroma:fakeid" + } + }, all_enqueued(worker: Pleroma.Workers.Publisher) + ) Pleroma.Config.put(config_path, initial_setting) end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 40344f17e..1d809164f 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -4,15 +4,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo + import Pleroma.Factory alias Pleroma.Activity alias Pleroma.Instances + alias Pleroma.ObanHelpers alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI + alias Pleroma.Workers.Receiver, as: ReceiverWorker setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -232,7 +236,8 @@ test "it inserts an incoming activity into the database", %{conn: conn} do |> post("/inbox", data) assert "ok" == json_response(conn, 200) - :timer.sleep(500) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) assert Activity.get_by_ap_id(data["id"]) end @@ -274,7 +279,7 @@ test "it inserts an incoming activity into the database", %{conn: conn, data: da |> post("/users/#{user.nickname}/inbox", data) assert "ok" == json_response(conn, 200) - :timer.sleep(500) + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) assert Activity.get_by_ap_id(data["id"]) end @@ -303,7 +308,7 @@ test "it accepts messages from actors that are followed by the user", %{ |> post("/users/#{recipient.nickname}/inbox", data) assert "ok" == json_response(conn, 200) - :timer.sleep(500) + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) assert Activity.get_by_ap_id(data["id"]) end @@ -382,6 +387,8 @@ test "it removes all follower collections but actor's", %{conn: conn} do |> post("/users/#{recipient.nickname}/inbox", data) |> json_response(200) + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + activity = Activity.get_by_ap_id(data["id"]) assert activity.id @@ -457,6 +464,7 @@ test "it inserts an incoming create activity into the database", %{conn: conn} d |> post("/users/#{user.nickname}/outbox", data) result = json_response(conn, 201) + assert Activity.get_by_ap_id(result["id"]) end diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 5c1704548..ebe962da2 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -4,8 +4,10 @@ defmodule Pleroma.Web.FederatorTest do alias Pleroma.Instances + alias Pleroma.ObanHelpers alias Pleroma.Web.CommonAPI alias Pleroma.Web.Federator + alias Pleroma.Workers.Publisher, as: PublisherWorker use Pleroma.DataCase use Oban.Testing, repo: Pleroma.Repo @@ -45,6 +47,7 @@ test "with relays active, it publishes to the relay", %{ } do with_mocks([relay_mock]) do Federator.publish(activity) + ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) end assert_received :relay_publish @@ -58,6 +61,7 @@ test "with relays deactivated, it does not publish to the relay", %{ with_mocks([relay_mock]) do Federator.publish(activity) + ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) end refute_received :relay_publish @@ -97,8 +101,15 @@ test "it federates only to reachable instances via AP" do expected_dt = NaiveDateTime.to_iso8601(dt) - assert [%{args: %{"params" => %{"inbox" => ^inbox1, "unreachable_since" => ^expected_dt}}}] = - all_enqueued(worker: Pleroma.Workers.Publisher) + ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) + + assert ObanHelpers.member?( + %{ + "op" => "publish_one", + "params" => %{"inbox" => inbox1, "unreachable_since" => expected_dt} + }, + all_enqueued(worker: PublisherWorker) + ) end test "it federates only to reachable instances via Websub" do @@ -129,16 +140,18 @@ test "it federates only to reachable instances via Websub" do expected_callback = sub2.callback expected_dt = NaiveDateTime.to_iso8601(dt) - assert [ + ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) + + assert ObanHelpers.member?( %{ - args: %{ - "params" => %{ - "callback" => ^expected_callback, - "unreachable_since" => ^expected_dt - } + "op" => "publish_one", + "params" => %{ + "callback" => expected_callback, + "unreachable_since" => expected_dt } - } - ] = all_enqueued(worker: Pleroma.Workers.Publisher) + }, + all_enqueued(worker: PublisherWorker) + ) end test "it federates only to reachable instances via Salmon" do @@ -172,16 +185,18 @@ test "it federates only to reachable instances via Salmon" do expected_dt = NaiveDateTime.to_iso8601(dt) - assert [ + ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) + + assert ObanHelpers.member?( %{ - args: %{ - "params" => %{ - "recipient_id" => ^remote_user2_id, - "unreachable_since" => ^expected_dt - } + "op" => "publish_one", + "params" => %{ + "recipient_id" => remote_user2_id, + "unreachable_since" => expected_dt } - } - ] = all_enqueued(worker: Pleroma.Workers.Publisher) + }, + all_enqueued(worker: PublisherWorker) + ) end end @@ -201,7 +216,8 @@ test "successfully processes incoming AP docs with correct origin" do "to" => ["https://www.w3.org/ns/activitystreams#Public"] } - {:ok, _activity} = Federator.incoming_ap_doc(params) + assert {:ok, job} = Federator.incoming_ap_doc(params) + assert {:ok, _activity} = ObanHelpers.perform(job) end test "rejects incoming AP docs with incorrect origin" do @@ -219,7 +235,8 @@ test "rejects incoming AP docs with incorrect origin" do "to" => ["https://www.w3.org/ns/activitystreams#Public"] } - :error = Federator.incoming_ap_doc(params) + assert {:ok, job} = Federator.incoming_ap_doc(params) + assert :error = ObanHelpers.perform(job) end end end diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs index 74386d7db..b704a558a 100644 --- a/test/web/websub/websub_test.exs +++ b/test/web/websub/websub_test.exs @@ -4,11 +4,14 @@ defmodule Pleroma.Web.WebsubTest do use Pleroma.DataCase + use Oban.Testing, repo: Pleroma.Repo + alias Pleroma.ObanHelpers alias Pleroma.Web.Router.Helpers alias Pleroma.Web.Websub alias Pleroma.Web.Websub.WebsubClientSubscription alias Pleroma.Web.Websub.WebsubServerSubscription + alias Pleroma.Workers.Subscriber, as: SubscriberWorker import Pleroma.Factory import Tesla.Mock @@ -224,6 +227,7 @@ test "it renews subscriptions that have less than a day of time left" do }) _refresh = Websub.refresh_subscriptions() + ObanHelpers.perform(all_enqueued(worker: SubscriberWorker)) assert still_good == Repo.get(WebsubClientSubscription, still_good.id) refute needs_refresh == Repo.get(WebsubClientSubscription, needs_refresh.id) From 33a5fc4a70b6f9b8c2d8c03a412d7eec8d5b3db1 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sat, 10 Aug 2019 20:38:31 +0300 Subject: [PATCH 003/272] [#1149] Fixed failing tests. Ensured Instance.set_unreachable/2 supports ISO 8601 datetime. --- lib/pleroma/digest_email_worker.ex | 4 +--- lib/pleroma/instances/instance.ex | 8 +++++++- test/conversation_test.exs | 2 ++ test/support/oban_helpers.ex | 6 ++++++ test/web/federator_test.exs | 3 ++- test/web/instances/instance_test.exs | 3 ++- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index 18e67d39b..3b0e2bca6 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -1,8 +1,6 @@ defmodule Pleroma.DigestEmailWorker do import Ecto.Query - @queue_name :digest_emails - def perform do config = Pleroma.Config.get([:email_notifications, :digest]) negative_interval = -Map.fetch!(config, :interval) @@ -17,7 +15,7 @@ def perform do select: u ) |> Pleroma.Repo.all() - |> Enum.each(&PleromaJobQueue.enqueue(@queue_name, __MODULE__, [&1])) + |> Enum.each(&PleromaJobQueue.enqueue(:digest_emails, __MODULE__, [&1])) end @doc """ diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index 4d7ed4ca1..544c4b687 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -90,7 +90,7 @@ def set_reachable(_), do: {:error, nil} def set_unreachable(url_or_host, unreachable_since \\ nil) def set_unreachable(url_or_host, unreachable_since) when is_binary(url_or_host) do - unreachable_since = unreachable_since || DateTime.utc_now() + unreachable_since = parse_datetime(unreachable_since) || NaiveDateTime.utc_now() host = host(url_or_host) existing_record = Repo.get_by(Instance, %{host: host}) @@ -114,4 +114,10 @@ def set_unreachable(url_or_host, unreachable_since) when is_binary(url_or_host) end def set_unreachable(_, _), do: {:error, nil} + + defp parse_datetime(datetime) when is_binary(datetime) do + NaiveDateTime.from_iso8601(datetime) + end + + defp parse_datetime(datetime), do: datetime end diff --git a/test/conversation_test.exs b/test/conversation_test.exs index aa193e0d4..2ebbcab76 100644 --- a/test/conversation_test.exs +++ b/test/conversation_test.exs @@ -28,6 +28,8 @@ test "it goes through old direct conversations" do {:ok, _activity} = CommonAPI.post(user, %{"visibility" => "direct", "status" => "hey @#{other_user.nickname}"}) + Pleroma.ObanHelpers.perform_all() + Repo.delete_all(Conversation) Repo.delete_all(Conversation.Participation) diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex index 54b5a9566..ecc03ba1a 100644 --- a/test/support/oban_helpers.ex +++ b/test/support/oban_helpers.ex @@ -9,6 +9,12 @@ defmodule Pleroma.ObanHelpers do alias Pleroma.Repo + def perform_all do + Oban.Job + |> Repo.all() + |> perform() + end + def perform(%Oban.Job{} = job) do res = apply(String.to_existing_atom("Elixir." <> job.worker), :perform, [job]) Repo.delete(job) diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index d3a28d50e..e0be4342b 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -249,7 +249,8 @@ test "it does not crash if MRF rejects the post" do File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - assert Federator.incoming_ap_doc(params) == :error + assert {:ok, job} = Federator.incoming_ap_doc(params) + assert :error = ObanHelpers.perform(job) Pleroma.Config.put([:instance, :rewrite_policy], policies) Pleroma.Config.put(:mrf_keyword, mrf_keyword_policy) diff --git a/test/web/instances/instance_test.exs b/test/web/instances/instance_test.exs index d28730994..a1bdd45d3 100644 --- a/test/web/instances/instance_test.exs +++ b/test/web/instances/instance_test.exs @@ -22,7 +22,8 @@ defmodule Pleroma.Instances.InstanceTest do describe "set_reachable/1" do test "clears `unreachable_since` of existing matching Instance record having non-nil `unreachable_since`" do - instance = insert(:instance, unreachable_since: NaiveDateTime.utc_now()) + unreachable_since = NaiveDateTime.to_iso8601(NaiveDateTime.utc_now()) + instance = insert(:instance, unreachable_since: unreachable_since) assert {:ok, instance} = Instance.set_reachable(instance.host) refute instance.unreachable_since From 0e1c481a94392b69833fbe6afc184ebbd90e1330 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 13 Aug 2019 20:20:26 +0300 Subject: [PATCH 004/272] [#1149] Added more oban workers. Refactoring. --- lib/pleroma/digest_email_worker.ex | 11 ++- lib/pleroma/scheduled_activity_worker.ex | 8 +- lib/pleroma/user.ex | 55 +++++++---- lib/pleroma/web/activity_pub/activity_pub.ex | 7 +- .../mrf/mediaproxy_warming_policy.ex | 12 ++- .../web/activity_pub/transmogrifier.ex | 7 +- lib/pleroma/web/federator/federator.ex | 98 ++++++++++++++++++- lib/pleroma/web/oauth/token/clean_worker.ex | 10 +- lib/pleroma/web/push/push.ex | 12 ++- .../controllers/util_controller.ex | 14 +-- lib/pleroma/workers/background_worker.ex | 66 +++++++++++++ lib/pleroma/workers/helper.ex | 13 +++ lib/pleroma/workers/mailer.ex | 18 ++++ lib/pleroma/workers/publisher.ex | 20 +--- lib/pleroma/workers/receiver.ex | 46 +-------- .../workers/scheduled_activity_worker.ex | 15 +++ lib/pleroma/workers/subscriber.ex | 23 +---- lib/pleroma/workers/transmogrifier.ex | 18 ++++ lib/pleroma/workers/web_pusher.ex | 19 ++++ test/activity_test.exs | 2 +- test/conversation_test.exs | 2 +- test/notification_test.exs | 5 +- test/support/oban_helpers.ex | 2 +- test/user_test.exs | 19 ++-- .../activity_pub_controller_test.exs | 2 +- .../mrf/mediaproxy_warming_policy_test.exs | 6 ++ test/web/activity_pub/transmogrifier_test.exs | 4 + test/web/federator_test.exs | 2 +- test/web/twitter_api/util_controller_test.exs | 43 ++++---- test/web/websub/websub_test.exs | 2 +- 30 files changed, 402 insertions(+), 159 deletions(-) create mode 100644 lib/pleroma/workers/background_worker.ex create mode 100644 lib/pleroma/workers/helper.ex create mode 100644 lib/pleroma/workers/mailer.ex create mode 100644 lib/pleroma/workers/scheduled_activity_worker.ex create mode 100644 lib/pleroma/workers/transmogrifier.ex create mode 100644 lib/pleroma/workers/web_pusher.ex diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index 3b0e2bca6..6e44cc955 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -1,6 +1,11 @@ defmodule Pleroma.DigestEmailWorker do + alias Pleroma.Repo + alias Pleroma.Workers.Mailer, as: MailerWorker + import Ecto.Query + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + def perform do config = Pleroma.Config.get([:email_notifications, :digest]) negative_interval = -Map.fetch!(config, :interval) @@ -15,7 +20,11 @@ def perform do select: u ) |> Pleroma.Repo.all() - |> Enum.each(&PleromaJobQueue.enqueue(:digest_emails, __MODULE__, [&1])) + |> Enum.each(fn user -> + %{"op" => "digest_email", "user_id" => user.id} + |> MailerWorker.new([queue: "digest_emails"] ++ worker_args(:digest_emails)) + |> Repo.insert() + end) end @doc """ diff --git a/lib/pleroma/scheduled_activity_worker.ex b/lib/pleroma/scheduled_activity_worker.ex index 65b38622f..cabea51ca 100644 --- a/lib/pleroma/scheduled_activity_worker.ex +++ b/lib/pleroma/scheduled_activity_worker.ex @@ -8,14 +8,18 @@ defmodule Pleroma.ScheduledActivityWorker do """ alias Pleroma.Config + alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.User alias Pleroma.Web.CommonAPI + use GenServer require Logger @schedule_interval :timer.minutes(1) + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + def start_link do GenServer.start_link(__MODULE__, nil) end @@ -45,7 +49,9 @@ def perform(:execute, scheduled_activity_id) do def handle_info(:perform, state) do ScheduledActivity.due_activities(@schedule_interval) |> Enum.each(fn scheduled_activity -> - PleromaJobQueue.enqueue(:scheduled_activities, __MODULE__, [:execute, scheduled_activity.id]) + %{"op" => "execute", "activity_id" => scheduled_activity.id} + |> Pleroma.Workers.ScheduledActivityWorker.new(worker_args(:scheduled_activities)) + |> Repo.insert() end) schedule_next() diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7d18f099e..bc2102ca7 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -26,6 +26,7 @@ defmodule Pleroma.User do alias Pleroma.Web.OStatus alias Pleroma.Web.RelMe alias Pleroma.Web.Websub + alias Pleroma.Workers.BackgroundWorker require Logger @@ -39,6 +40,8 @@ defmodule Pleroma.User do @strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/ @extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/ + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + schema "users" do field(:bio, :string) field(:email, :string) @@ -579,8 +582,11 @@ def get_or_fetch_by_nickname(nickname) do end @doc "Fetch some posts when the user has just been federated with" - def fetch_initial_posts(user), - do: PleromaJobQueue.enqueue(:background, __MODULE__, [:fetch_initial_posts, user]) + def fetch_initial_posts(user) do + %{"op" => "fetch_initial_posts", "user_id" => user.id} + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() + end @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() def get_followers_query(%User{} = user, nil) do @@ -1001,7 +1007,9 @@ def unblock_domain(user, domain) do end def deactivate_async(user, status \\ true) do - PleromaJobQueue.enqueue(:background, __MODULE__, [:deactivate_async, user, status]) + %{"op" => "deactivate_user", "user_id" => user.id, "status" => status} + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() end def deactivate(%User{} = user, status \\ true) do @@ -1029,9 +1037,11 @@ def update_notification_settings(%User{} = user, settings \\ %{}) do |> update_and_set_cache() end - @spec delete(User.t()) :: :ok - def delete(%User{} = user), - do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user]) + def delete(%User{} = user) do + %{"op" => "delete_user", "user_id" => user.id} + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() + end @spec perform(atom(), User.t()) :: {:ok, User.t()} def perform(:delete, %User{} = user) do @@ -1138,21 +1148,26 @@ def external_users(opts \\ []) do Repo.all(query) end - def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers), - do: - PleromaJobQueue.enqueue(:background, __MODULE__, [ - :blocks_import, - blocker, - blocked_identifiers - ]) + def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do + %{ + "op" => "blocks_import", + "blocker_id" => blocker.id, + "blocked_identifiers" => blocked_identifiers + } + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() + end - def follow_import(%User{} = follower, followed_identifiers) when is_list(followed_identifiers), - do: - PleromaJobQueue.enqueue(:background, __MODULE__, [ - :follow_import, - follower, - followed_identifiers - ]) + def follow_import(%User{} = follower, followed_identifiers) + when is_list(followed_identifiers) do + %{ + "op" => "follow_import", + "follower_id" => follower.id, + "followed_identifiers" => followed_identifiers + } + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() + end def delete_user_activities(%User{ap_id: ap_id} = user) do ap_id diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1a279a7df..8be8ac86f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -17,6 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.WebFinger + alias Pleroma.Workers.BackgroundWorker import Ecto.Query import Pleroma.Web.ActivityPub.Utils @@ -25,6 +26,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do require Logger require Pleroma.Constants + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + # For Announce activities, we filter the recipients based on following status for any actors # that match actual users. See issue #164 for more information about why this is necessary. defp get_recipients(%{"type" => "Announce"} = data) do @@ -145,7 +148,9 @@ def insert(map, local \\ true, fake \\ false) when is_map(map) do activity end - PleromaJobQueue.enqueue(:background, Pleroma.Web.RichMedia.Helpers, [:fetch, activity]) + %{"op" => "fetch_data_for_activity", "activity_id" => activity.id} + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() Notification.create_notifications(activity) diff --git a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex index 01d21a299..1df3bb5b6 100644 --- a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex @@ -7,7 +7,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do @behaviour Pleroma.Web.ActivityPub.MRF alias Pleroma.HTTP + alias Pleroma.Repo alias Pleroma.Web.MediaProxy + alias Pleroma.Workers.BackgroundWorker require Logger @@ -16,6 +18,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do recv_timeout: 10_000 ] + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + def perform(:prefetch, url) do Logger.info("Prefetching #{inspect(url)}") @@ -30,7 +34,9 @@ def perform(:preload, %{"object" => %{"attachment" => attachments}} = _message) url |> Enum.each(fn %{"href" => href} -> - PleromaJobQueue.enqueue(:background, __MODULE__, [:prefetch, href]) + %{"op" => "media_proxy_prefetch", "url" => href} + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() x -> Logger.debug("Unhandled attachment URL object #{inspect(x)}") @@ -46,7 +52,9 @@ def filter( %{"type" => "Create", "object" => %{"attachment" => attachments} = _object} = message ) when is_list(attachments) and length(attachments) > 0 do - PleromaJobQueue.enqueue(:background, __MODULE__, [:preload, message]) + %{"op" => "media_proxy_preload", "message" => message} + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() {:ok, message} end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 5403b71d8..0f117cd04 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -15,12 +15,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator + alias Pleroma.Workers.Transmogrifier, as: TransmogrifierWorker import Ecto.Query require Logger require Pleroma.Constants + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + @doc """ Modifies an incoming AP object (mastodon format) to our internal format. """ @@ -1073,7 +1076,9 @@ def upgrade_user_from_ap_id(ap_id) do already_ap <- User.ap_enabled?(user), {:ok, user} <- user |> User.upgrade_changeset(data) |> User.update_and_set_cache() do unless already_ap do - PleromaJobQueue.enqueue(:transmogrifier, __MODULE__, [:user_upgrade, user]) + %{"op" => "user_upgrade", "user_id" => user.id} + |> TransmogrifierWorker.new(worker_args(:transmogrifier)) + |> Repo.insert() end {:ok, user} diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index bb9eadfee..d85fe824f 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -3,12 +3,23 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Federator do + alias Pleroma.Activity + alias Pleroma.Object.Containment + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.Federator.Publisher + alias Pleroma.Web.OStatus + alias Pleroma.Web.Websub alias Pleroma.Workers.Publisher, as: PublisherWorker alias Pleroma.Workers.Receiver, as: ReceiverWorker alias Pleroma.Workers.Subscriber, as: SubscriberWorker require Logger + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + def init do # 1 minute refresh_subscriptions(schedule_in: 60) @@ -41,7 +52,7 @@ def incoming_ap_doc(params) do end def publish(%{id: "pleroma:fakeid"} = activity) do - PublisherWorker.perform_publish(activity) + perform(:publish, activity) end def publish(activity) do @@ -68,11 +79,88 @@ def refresh_subscriptions(worker_args \\ []) do |> Pleroma.Repo.insert() end - defp worker_args(queue) do - if max_attempts = Pleroma.Config.get([:workers, :retries, queue]) do - [max_attempts: max_attempts] + # Job Worker Callbacks + + @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()} + def perform(:publish_one, module, params) do + apply(module, :publish_one, [params]) + end + + def perform(:publish, activity) do + Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end) + + with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]), + {:ok, actor} <- User.ensure_keys_present(actor) do + Publisher.publish(actor, activity) + end + end + + def perform(:incoming_doc, doc) do + Logger.info("Got document, trying to parse") + OStatus.handle_incoming(doc) + end + + def perform(:incoming_ap_doc, params) do + Logger.info("Handling incoming AP activity") + + params = Utils.normalize_params(params) + + # NOTE: we use the actor ID to do the containment, this is fine because an + # 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, activity} <- Transmogrifier.handle_incoming(params) do + {:ok, activity} else - [] + %Activity{} -> + Logger.info("Already had #{params["id"]}") + :error + + _e -> + # Just drop those for now + Logger.info("Unhandled activity") + Logger.info(Jason.encode!(params, pretty: true)) + :error + end + end + + def perform(:request_subscription, websub) do + Logger.debug("Refreshing #{websub.topic}") + + with {:ok, websub} <- Websub.request_subscription(websub) do + Logger.debug("Successfully refreshed #{websub.topic}") + else + _e -> Logger.debug("Couldn't refresh #{websub.topic}") + end + end + + def perform(:verify_websub, websub) do + Logger.debug(fn -> + "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})" + end) + + Websub.verify(websub) + end + + def perform(:refresh_subscriptions) do + Logger.debug("Federator running refresh subscriptions") + Websub.refresh_subscriptions() + + spawn(fn -> + # 6 hours + Process.sleep(1000 * 60 * 60 * 6) + refresh_subscriptions() + end) + end + + def ap_enabled_actor(id) do + user = User.get_cached_by_ap_id(id) + + if User.ap_enabled?(user) do + {:ok, user} + else + ActivityPub.make_user_from_ap_id(id) end end end diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex index dca852449..c0c9c3653 100644 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -14,9 +14,12 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do [:oauth2, :clean_expired_tokens_interval], 86_400_000 ) - @queue :background + alias Pleroma.Repo alias Pleroma.Web.OAuth.Token + alias Pleroma.Workers.BackgroundWorker + + defdelegate worker_args(queue), to: Pleroma.Workers.Helper def start_link, do: GenServer.start_link(__MODULE__, nil) @@ -31,8 +34,11 @@ def init(_) do @doc false def handle_info(:perform, state) do + %{"op" => "clean_expired_tokens"} + |> BackgroundWorker.new(worker_args(:background)) + |> Repo.insert() + Process.send_after(self(), :perform, @interval) - PleromaJobQueue.enqueue(@queue, __MODULE__, [:clean]) {:noreply, state} end diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex index 729dad02a..b4f0e5127 100644 --- a/lib/pleroma/web/push/push.ex +++ b/lib/pleroma/web/push/push.ex @@ -3,10 +3,13 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Push do - alias Pleroma.Web.Push.Impl + alias Pleroma.Repo + alias Pleroma.Workers.WebPusher require Logger + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + def init do unless enabled() do Logger.warn(""" @@ -31,6 +34,9 @@ def enabled do end end - def send(notification), - do: PleromaJobQueue.enqueue(:web_push, Impl, [notification]) + def send(notification) do + %{"op" => "web_push", "notification_id" => notification.id} + |> WebPusher.new(worker_args(:web_push)) + |> Repo.insert() + end end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 3405bd3b7..7ba4ad305 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -265,12 +265,7 @@ def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do String.split(line, ",") |> List.first() end) |> List.delete("Account address") do - PleromaJobQueue.enqueue(:background, User, [ - :follow_import, - follower, - followed_identifiers - ]) - + User.follow_import(follower, followed_identifiers) json(conn, "job started") end end @@ -281,12 +276,7 @@ def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do with blocked_identifiers <- String.split(list) do - PleromaJobQueue.enqueue(:background, User, [ - :blocks_import, - blocker, - blocked_identifiers - ]) - + User.blocks_import(blocker, blocked_identifiers) json(conn, "job started") end end diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex new file mode 100644 index 000000000..3ab2b6bcc --- /dev/null +++ b/lib/pleroma/workers/background_worker.ex @@ -0,0 +1,66 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.BackgroundWorker do + alias Pleroma.Activity + alias Pleroma.User + alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy + alias Pleroma.Web.OAuth.Token.CleanWorker + + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "background", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + + @impl Oban.Worker + def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}) do + user = User.get_by_id(user_id) + User.perform(:fetch_initial_posts, user) + end + + def perform(%{"op" => "deactivate_user", "user_id" => user_id, "status" => status}) do + user = User.get_by_id(user_id) + User.perform(:deactivate_async, user, status) + end + + def perform(%{"op" => "delete_user", "user_id" => user_id}) do + user = User.get_by_id(user_id) + User.perform(:delete, user) + end + + def perform(%{ + "op" => "blocks_import", + "blocker_id" => blocker_id, + "blocked_identifiers" => blocked_identifiers + }) do + blocker = User.get_by_id(blocker_id) + User.perform(:blocks_import, blocker, blocked_identifiers) + end + + def perform(%{ + "op" => "follow_import", + "follower_id" => follower_id, + "followed_identifiers" => followed_identifiers + }) do + follower = User.get_by_id(follower_id) + User.perform(:follow_import, follower, followed_identifiers) + end + + def perform(%{"op" => "clean_expired_tokens"}) do + CleanWorker.perform(:clean) + end + + def perform(%{"op" => "media_proxy_preload", "message" => message}) do + MediaProxyWarmingPolicy.perform(:preload, message) + end + + def perform(%{"op" => "media_proxy_prefetch", "url" => url}) do + MediaProxyWarmingPolicy.perform(:prefetch, url) + end + + def perform(%{"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 +end diff --git a/lib/pleroma/workers/helper.ex b/lib/pleroma/workers/helper.ex new file mode 100644 index 000000000..3286ce0e8 --- /dev/null +++ b/lib/pleroma/workers/helper.ex @@ -0,0 +1,13 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Helper do + def worker_args(queue) do + if max_attempts = Pleroma.Config.get([:workers, :retries, queue]) do + [max_attempts: max_attempts] + else + [] + end + end +end diff --git a/lib/pleroma/workers/mailer.ex b/lib/pleroma/workers/mailer.ex new file mode 100644 index 000000000..da7fa6fd5 --- /dev/null +++ b/lib/pleroma/workers/mailer.ex @@ -0,0 +1,18 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Mailer do + alias Pleroma.User + + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "mailer", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + + @impl Oban.Worker + def perform(%{"op" => "digest_email", "user_id" => user_id}) do + user = User.get_by_id(user_id) + Pleroma.DigestEmailWorker.perform(user) + end +end diff --git a/lib/pleroma/workers/publisher.ex b/lib/pleroma/workers/publisher.ex index 67871977a..c890ffb79 100644 --- a/lib/pleroma/workers/publisher.ex +++ b/lib/pleroma/workers/publisher.ex @@ -4,7 +4,7 @@ defmodule Pleroma.Workers.Publisher do alias Pleroma.Activity - alias Pleroma.User + alias Pleroma.Web.Federator # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, @@ -13,23 +13,11 @@ defmodule Pleroma.Workers.Publisher do @impl Oban.Worker def perform(%{"op" => "publish", "activity_id" => activity_id}) do - with %Activity{} = activity <- Activity.get_by_id(activity_id) do - perform_publish(activity) - else - _ -> raise "Non-existing activity: #{activity_id}" - end + activity = Activity.get_by_id(activity_id) + Federator.perform(:publish, activity) end def perform(%{"op" => "publish_one", "module" => module_name, "params" => params}) do - module_name - |> String.to_atom() - |> apply(:publish_one, [params]) - end - - def perform_publish(%Activity{} = activity) do - with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]), - {:ok, actor} <- User.ensure_keys_present(actor) do - Pleroma.Web.Federator.Publisher.publish(actor, activity) - end + Federator.perform(:publish_one, String.to_atom(module_name), params) end end diff --git a/lib/pleroma/workers/receiver.ex b/lib/pleroma/workers/receiver.ex index 43558b4e6..d3de95716 100644 --- a/lib/pleroma/workers/receiver.ex +++ b/lib/pleroma/workers/receiver.ex @@ -3,15 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.Receiver do - alias Pleroma.Activity - alias Pleroma.Object.Containment - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.OStatus - - require Logger + alias Pleroma.Web.Federator # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, @@ -20,42 +12,10 @@ defmodule Pleroma.Workers.Receiver do @impl Oban.Worker def perform(%{"op" => "incoming_doc", "body" => doc}) do - Logger.info("Got incoming document, trying to parse") - OStatus.handle_incoming(doc) + Federator.perform(:incoming_doc, doc) end def perform(%{"op" => "incoming_ap_doc", "params" => params}) do - Logger.info("Handling incoming AP activity") - - params = Utils.normalize_params(params) - - # NOTE: we use the actor ID to do the containment, this is fine because an - # 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, activity} <- Transmogrifier.handle_incoming(params) do - {:ok, activity} - else - %Activity{} -> - Logger.info("Already had #{params["id"]}") - :error - - _e -> - # Just drop those for now - Logger.info("Unhandled activity") - Logger.info(Jason.encode!(params, pretty: true)) - :error - end - end - - defp ap_enabled_actor(id) do - user = User.get_cached_by_ap_id(id) - - if User.ap_enabled?(user) do - {:ok, user} - else - ActivityPub.make_user_from_ap_id(id) - end + Federator.perform(:incoming_ap_doc, params) end end diff --git a/lib/pleroma/workers/scheduled_activity_worker.ex b/lib/pleroma/workers/scheduled_activity_worker.ex new file mode 100644 index 000000000..a49834fd8 --- /dev/null +++ b/lib/pleroma/workers/scheduled_activity_worker.ex @@ -0,0 +1,15 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.ScheduledActivityWorker do + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "scheduled_activities", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + + @impl Oban.Worker + def perform(%{"op" => "execute", "activity_id" => activity_id}) do + Pleroma.ScheduledActivityWorker.perform(:execute, activity_id) + end +end diff --git a/lib/pleroma/workers/subscriber.ex b/lib/pleroma/workers/subscriber.ex index a8c01bb10..6af3ad0a1 100644 --- a/lib/pleroma/workers/subscriber.ex +++ b/lib/pleroma/workers/subscriber.ex @@ -4,11 +4,9 @@ defmodule Pleroma.Workers.Subscriber do alias Pleroma.Repo - alias Pleroma.Web.Websub + alias Pleroma.Web.Federator alias Pleroma.Web.Websub.WebsubClientSubscription - require Logger - # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "federator_outgoing", @@ -16,29 +14,16 @@ defmodule Pleroma.Workers.Subscriber do @impl Oban.Worker def perform(%{"op" => "refresh_subscriptions"}) do - Websub.refresh_subscriptions() - # Schedule the next run in 6 hours - Pleroma.Web.Federator.refresh_subscriptions(schedule_in: 3600 * 6) + Federator.perform(:refresh_subscriptions) end def perform(%{"op" => "request_subscription", "websub_id" => websub_id}) do websub = Repo.get(WebsubClientSubscription, websub_id) - Logger.debug("Refreshing #{websub.topic}") - - with {:ok, websub} <- Websub.request_subscription(websub) do - Logger.debug("Successfully refreshed #{websub.topic}") - else - _e -> Logger.debug("Couldn't refresh #{websub.topic}") - end + Federator.perform(:request_subscription, websub) end def perform(%{"op" => "verify_websub", "websub_id" => websub_id}) do websub = Repo.get(WebsubClientSubscription, websub_id) - - Logger.debug(fn -> - "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})" - end) - - Websub.verify(websub) + Federator.perform(:verify_websub, websub) end end diff --git a/lib/pleroma/workers/transmogrifier.ex b/lib/pleroma/workers/transmogrifier.ex new file mode 100644 index 000000000..c6b4fab47 --- /dev/null +++ b/lib/pleroma/workers/transmogrifier.ex @@ -0,0 +1,18 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Transmogrifier do + alias Pleroma.User + + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "transmogrifier", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + + @impl Oban.Worker + def perform(%{"op" => "user_upgrade", "user_id" => user_id}) do + user = User.get_by_id(user_id) + Pleroma.Web.ActivityPub.Transmogrifier.perform(:user_upgrade, user) + end +end diff --git a/lib/pleroma/workers/web_pusher.ex b/lib/pleroma/workers/web_pusher.ex new file mode 100644 index 000000000..b99581eb0 --- /dev/null +++ b/lib/pleroma/workers/web_pusher.ex @@ -0,0 +1,19 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.WebPusher do + alias Pleroma.Notification + alias Pleroma.Repo + + # Note: `max_attempts` is intended to be overridden in `new/1` call + use Oban.Worker, + queue: "web_push", + max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + + @impl Oban.Worker + def perform(%{"op" => "web_push", "notification_id" => notification_id}) do + notification = Repo.get(Notification, notification_id) + Pleroma.Web.Push.Impl.perform(notification) + end +end diff --git a/test/activity_test.exs b/test/activity_test.exs index b9c12adb2..658c47837 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -6,8 +6,8 @@ defmodule Pleroma.ActivityTest do use Pleroma.DataCase alias Pleroma.Activity alias Pleroma.Bookmark - alias Pleroma.ObanHelpers alias Pleroma.Object + alias Pleroma.Tests.ObanHelpers alias Pleroma.ThreadMute import Pleroma.Factory diff --git a/test/conversation_test.exs b/test/conversation_test.exs index 2ebbcab76..f917aa691 100644 --- a/test/conversation_test.exs +++ b/test/conversation_test.exs @@ -28,7 +28,7 @@ test "it goes through old direct conversations" do {:ok, _activity} = CommonAPI.post(user, %{"visibility" => "direct", "status" => "hey @#{other_user.nickname}"}) - Pleroma.ObanHelpers.perform_all() + Pleroma.Tests.ObanHelpers.perform_all() Repo.delete_all(Conversation) Repo.delete_all(Conversation.Participation) diff --git a/test/notification_test.exs b/test/notification_test.exs index 80ea2a085..e1c9f4f93 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.NotificationTest do import Pleroma.Factory alias Pleroma.Notification + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.CommonAPI @@ -621,7 +622,8 @@ test "notifications are deleted if a local user is deleted" do refute Enum.empty?(Notification.for_user(other_user)) - User.delete(user) + {:ok, job} = User.delete(user) + ObanHelpers.perform(job) assert Enum.empty?(Notification.for_user(other_user)) end @@ -666,6 +668,7 @@ test "notifications are deleted if a remote user is deleted" do } {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message) + ObanHelpers.perform_all() assert Enum.empty?(Notification.for_user(local_user)) end diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex index ecc03ba1a..d379c9ec7 100644 --- a/test/support/oban_helpers.ex +++ b/test/support/oban_helpers.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2018 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.ObanHelpers do +defmodule Pleroma.Tests.ObanHelpers do @moduledoc """ Oban test helpers. """ diff --git a/test/user_test.exs b/test/user_test.exs index 8617752d7..9c2117a0b 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -5,9 +5,9 @@ defmodule Pleroma.UserTest do alias Pleroma.Activity alias Pleroma.Builders.UserBuilder - alias Pleroma.ObanHelpers alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI @@ -676,7 +676,9 @@ test "it imports user followings from list" do user3.nickname ] - result = User.follow_import(user1, identifiers) + {:ok, job} = User.follow_import(user1, identifiers) + result = ObanHelpers.perform(job) + assert is_list(result) assert result == [user2, user3] end @@ -887,7 +889,9 @@ test "it imports user blocks from list" do user3.nickname ] - result = User.blocks_import(user1, identifiers) + {:ok, job} = User.blocks_import(user1, identifiers) + result = ObanHelpers.perform(job) + assert is_list(result) assert result == [user2, user3] end @@ -1013,7 +1017,8 @@ test "it deletes a user, all follow relationships and all activities", %{user: u {:ok, like_two, _} = CommonAPI.favorite(activity.id, follower) {:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user) - {:ok, _} = User.delete(user) + {:ok, job} = User.delete(user) + {:ok, _user} = ObanHelpers.perform(job) follower = User.get_cached_by_id(follower.id) @@ -1043,7 +1048,8 @@ test "it sends out User Delete activity", %{user: user} do {:ok, follower} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin") {:ok, _} = User.follow(follower, user) - {:ok, _user} = User.delete(user) + {:ok, job} = User.delete(user) + {:ok, _user} = ObanHelpers.perform(job) assert ObanHelpers.member?( %{ @@ -1100,7 +1106,8 @@ test "invalidate_cache works" do test "User.delete() plugs any possible zombie objects" do user = insert(:user) - {:ok, _} = User.delete(user) + {:ok, job} = User.delete(user) + {:ok, _} = ObanHelpers.perform(job) {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index d7f0a8264..f46353fdd 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -9,8 +9,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do import Pleroma.Factory alias Pleroma.Activity alias Pleroma.Instances - alias Pleroma.ObanHelpers alias Pleroma.Object + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.UserView diff --git a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs index 372e789be..95a809d25 100644 --- a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs +++ b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do use Pleroma.DataCase alias Pleroma.HTTP + alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy import Mock @@ -24,6 +25,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do test "it prefetches media proxy URIs" do 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 diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index e7498e005..52f46c141 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do alias Pleroma.Object alias Pleroma.Object.Fetcher alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier @@ -563,6 +564,7 @@ test "it works for incoming user deletes" do |> Poison.decode!() {:ok, _} = Transmogrifier.handle_incoming(data) + ObanHelpers.perform_all() refute User.get_cached_by_ap_id(ap_id) end @@ -1132,6 +1134,8 @@ test "it upgrades a user to activitypub" do assert user.info.note_count == 1 {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") + ObanHelpers.perform_all() + assert user.info.ap_enabled assert user.info.note_count == 1 assert user.follower_address == "https://niu.moe/users/rye/followers" diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index e0be4342b..9ca341b6d 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Web.FederatorTest do alias Pleroma.Instances - alias Pleroma.ObanHelpers + alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.CommonAPI alias Pleroma.Web.Federator alias Pleroma.Workers.Publisher, as: PublisherWorker diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 640579c09..e3f129f72 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -4,9 +4,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Notification alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -50,8 +52,7 @@ test "it imports follow lists from file", %{conn: conn} do {File, [], read!: fn "follow_list.txt" -> "Account address,Show boosts\n#{user2.ap_id},true" - end}, - {PleromaJobQueue, [:passthrough], []} + end} ]) do response = conn @@ -59,15 +60,16 @@ test "it imports follow lists from file", %{conn: conn} do |> post("/api/pleroma/follow_import", %{"list" => %Plug.Upload{path: "follow_list.txt"}}) |> json_response(:ok) - assert called( - PleromaJobQueue.enqueue( - :background, - User, - [:follow_import, user1, [user2.ap_id]] - ) - ) - assert response == "job started" + + assert ObanHelpers.member?( + %{ + "op" => "follow_import", + "follower_id" => user1.id, + "followed_identifiers" => [user2.ap_id] + }, + all_enqueued(worker: Pleroma.Workers.BackgroundWorker) + ) end end @@ -126,8 +128,7 @@ test "it imports blocks users from file", %{conn: conn} do user3 = insert(:user) with_mocks([ - {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}, - {PleromaJobQueue, [:passthrough], []} + {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end} ]) do response = conn @@ -135,15 +136,16 @@ test "it imports blocks users from file", %{conn: conn} do |> post("/api/pleroma/blocks_import", %{"list" => %Plug.Upload{path: "blocks_list.txt"}}) |> json_response(:ok) - assert called( - PleromaJobQueue.enqueue( - :background, - User, - [:blocks_import, user1, [user2.ap_id, user3.ap_id]] - ) - ) - assert response == "job started" + + assert ObanHelpers.member?( + %{ + "op" => "blocks_import", + "blocker_id" => user1.id, + "blocked_identifiers" => [user2.ap_id, user3.ap_id] + }, + all_enqueued(worker: Pleroma.Workers.BackgroundWorker) + ) end end end @@ -607,6 +609,7 @@ test "it returns HTTP 200", %{conn: conn} do |> json_response(:ok) assert response == %{"status" => "success"} + ObanHelpers.perform_all() user = User.get_cached_by_id(user.id) diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs index b704a558a..414610879 100644 --- a/test/web/websub/websub_test.exs +++ b/test/web/websub/websub_test.exs @@ -6,7 +6,7 @@ defmodule Pleroma.Web.WebsubTest do use Pleroma.DataCase use Oban.Testing, repo: Pleroma.Repo - alias Pleroma.ObanHelpers + alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.Router.Helpers alias Pleroma.Web.Websub alias Pleroma.Web.Websub.WebsubClientSubscription From a180c1360ecdbed76eccf3435bb2c831356746bc Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 14 Aug 2019 21:42:21 +0300 Subject: [PATCH 005/272] [#1149] Oban mailer job. Adjusted tests. --- lib/pleroma/application.ex | 1 + lib/pleroma/emails/mailer.ex | 13 ++++++++++++- lib/pleroma/workers/mailer.ex | 9 +++++++++ test/mix/tasks/pleroma.digest_test.exs | 3 +++ .../mastodon_api/mastodon_api_controller_test.exs | 4 ++++ .../web/twitter_api/twitter_api_controller_test.exs | 4 ++++ test/web/twitter_api/twitter_api_test.exs | 2 ++ 7 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 5550a4902..7cf60f44a 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -233,6 +233,7 @@ defp hackney_pool_children do defp after_supervisor_start do with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], true <- digest_config[:active] do + # TODO: consider replacing with `quantum` scheduler PleromaJobQueue.schedule( digest_config[:schedule], :digest_emails, diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex index 2e4657b7c..bb534f602 100644 --- a/lib/pleroma/emails/mailer.ex +++ b/lib/pleroma/emails/mailer.ex @@ -9,6 +9,8 @@ defmodule Pleroma.Emails.Mailer do The module contains functions to delivery email using Swoosh.Mailer. """ + alias Pleroma.Repo + alias Pleroma.Workers.Mailer, as: MailerWorker alias Swoosh.DeliveryError @otp_app :pleroma @@ -17,9 +19,18 @@ defmodule Pleroma.Emails.Mailer do @spec enabled?() :: boolean() def enabled?, do: Pleroma.Config.get([__MODULE__, :enabled]) + defdelegate worker_args(queue), to: Pleroma.Workers.Helper + @doc "add email to queue" def deliver_async(email, config \\ []) do - PleromaJobQueue.enqueue(:mailer, __MODULE__, [:deliver_async, email, config]) + encoded_email = + email + |> :erlang.term_to_binary() + |> Base.encode64() + + %{"op" => "email", "encoded_email" => encoded_email, "config" => config} + |> MailerWorker.new(worker_args(:mailer)) + |> Repo.insert() end @doc "callback to perform send email from queue" diff --git a/lib/pleroma/workers/mailer.ex b/lib/pleroma/workers/mailer.ex index da7fa6fd5..8bf9952bc 100644 --- a/lib/pleroma/workers/mailer.ex +++ b/lib/pleroma/workers/mailer.ex @@ -11,6 +11,15 @@ defmodule Pleroma.Workers.Mailer do max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) @impl Oban.Worker + def perform(%{"op" => "email", "encoded_email" => encoded_email, "config" => config}) do + email = + encoded_email + |> Base.decode64!() + |> :erlang.binary_to_term() + + Pleroma.Emails.Mailer.deliver(email, config) + end + def perform(%{"op" => "digest_email", "user_id" => user_id}) do user = User.get_by_id(user_id) Pleroma.DigestEmailWorker.perform(user) diff --git a/test/mix/tasks/pleroma.digest_test.exs b/test/mix/tasks/pleroma.digest_test.exs index 595f64ed7..5fbeac0d6 100644 --- a/test/mix/tasks/pleroma.digest_test.exs +++ b/test/mix/tasks/pleroma.digest_test.exs @@ -4,6 +4,7 @@ defmodule Mix.Tasks.Pleroma.DigestTest do import Pleroma.Factory import Swoosh.TestAssertions + alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.CommonAPI setup_all do @@ -39,6 +40,8 @@ test "Sends digest to the given user" do :ok = Mix.Tasks.Pleroma.Digest.run(["test", user2.nickname, yesterday_date]) + ObanHelpers.perform_all() + assert_receive {:mix_shell, :info, [message]} assert message =~ "Digest email have been sent" diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index e49c4cc22..be9ff2568 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -11,6 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Pleroma.Object alias Pleroma.Repo alias Pleroma.ScheduledActivity + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI @@ -3871,6 +3872,7 @@ test "it creates a PasswordResetToken record for user", %{user: user} do end test "it sends an email to user", %{user: user} do + ObanHelpers.perform_all() token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) @@ -3934,6 +3936,8 @@ test "resend account confirmation email", %{conn: conn, user: user} do |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}") |> json_response(:no_content) + ObanHelpers.perform_all() + email = Pleroma.Emails.UserEmail.account_confirmation_email(user) notify_email = Pleroma.Config.get([:instance, :notify_email]) instance_name = Pleroma.Config.get([:instance, :name]) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 8bb8aa36d..9ac4ff929 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -12,6 +12,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI @@ -1099,6 +1100,7 @@ test "it creates a PasswordResetToken record for user", %{user: user} do end test "it sends an email to user", %{user: user} do + ObanHelpers.perform_all() token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) @@ -1209,6 +1211,8 @@ test "it sends confirmation email", %{conn: conn, user: user} do |> assign(:user, user) |> post("/api/account/resend_confirmation_email?email=#{user.email}") + ObanHelpers.perform_all() + email = Pleroma.Emails.UserEmail.account_confirmation_email(user) notify_email = Pleroma.Config.get([:instance, :notify_email]) instance_name = Pleroma.Config.get([:instance, :name]) diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index cbe83852e..bf063a0de 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do alias Pleroma.Activity alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.UserInviteToken alias Pleroma.Web.ActivityPub.ActivityPub @@ -321,6 +322,7 @@ test "it sends confirmation email if :account_activation_required is specified i } {:ok, user} = TwitterAPI.register_user(data) + ObanHelpers.perform_all() assert user.info.confirmation_pending From c29686309eaf2cdae039ce813755c0e23cdc4a03 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 23 Aug 2019 09:23:10 +0300 Subject: [PATCH 006/272] [#1149] Upgraded `oban` from 0.6.0 to 0.7.1. --- config/config.exs | 1 - lib/pleroma/application.ex | 5 +-- lib/pleroma/workers/background_worker.ex | 42 +++++++++++-------- lib/pleroma/workers/mailer.ex | 6 +-- lib/pleroma/workers/publisher.ex | 6 +-- lib/pleroma/workers/receiver.ex | 6 +-- .../workers/scheduled_activity_worker.ex | 4 +- lib/pleroma/workers/subscriber.ex | 8 ++-- lib/pleroma/workers/transmogrifier.ex | 4 +- lib/pleroma/workers/web_pusher.ex | 4 +- mix.exs | 2 +- mix.lock | 10 ++--- test/support/oban_helpers.ex | 2 +- 13 files changed, 51 insertions(+), 49 deletions(-) diff --git a/config/config.exs b/config/config.exs index 9794997d9..1a6348bcd 100644 --- a/config/config.exs +++ b/config/config.exs @@ -469,7 +469,6 @@ config :pleroma, :workers, retries: [ - compile_time_default: 1, federator_incoming: 5, federator_outgoing: 5 ] diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 2e2922d28..384b03aa9 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -41,10 +41,7 @@ def start(_type, _args) do hackney_pool_children() ++ [ Pleroma.Stats, - %{ - id: Oban, - start: {Oban, :start_link, [Application.get_env(:pleroma, Oban)]} - }, + {Oban, Application.get_env(:pleroma, Oban)}, %{ id: :web_push_init, start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 3ab2b6bcc..3c021b9b4 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -11,55 +11,61 @@ defmodule Pleroma.Workers.BackgroundWorker do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "background", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}) do + def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}, _job) do user = User.get_by_id(user_id) User.perform(:fetch_initial_posts, user) end - def perform(%{"op" => "deactivate_user", "user_id" => user_id, "status" => status}) do + def perform(%{"op" => "deactivate_user", "user_id" => user_id, "status" => status}, _job) do user = User.get_by_id(user_id) User.perform(:deactivate_async, user, status) end - def perform(%{"op" => "delete_user", "user_id" => user_id}) do + def perform(%{"op" => "delete_user", "user_id" => user_id}, _job) do user = User.get_by_id(user_id) User.perform(:delete, user) end - def perform(%{ - "op" => "blocks_import", - "blocker_id" => blocker_id, - "blocked_identifiers" => blocked_identifiers - }) do + def perform( + %{ + "op" => "blocks_import", + "blocker_id" => blocker_id, + "blocked_identifiers" => blocked_identifiers + }, + _job + ) do blocker = User.get_by_id(blocker_id) User.perform(:blocks_import, blocker, blocked_identifiers) end - def perform(%{ - "op" => "follow_import", - "follower_id" => follower_id, - "followed_identifiers" => followed_identifiers - }) do + def perform( + %{ + "op" => "follow_import", + "follower_id" => follower_id, + "followed_identifiers" => followed_identifiers + }, + _job + ) do follower = User.get_by_id(follower_id) User.perform(:follow_import, follower, followed_identifiers) end - def perform(%{"op" => "clean_expired_tokens"}) do + def perform(%{"op" => "clean_expired_tokens"}, _job) do CleanWorker.perform(:clean) end - def perform(%{"op" => "media_proxy_preload", "message" => message}) do + def perform(%{"op" => "media_proxy_preload", "message" => message}, _job) do MediaProxyWarmingPolicy.perform(:preload, message) end - def perform(%{"op" => "media_proxy_prefetch", "url" => url}) do + def perform(%{"op" => "media_proxy_prefetch", "url" => url}, _job) do MediaProxyWarmingPolicy.perform(:prefetch, url) end - def perform(%{"op" => "fetch_data_for_activity", "activity_id" => activity_id}) do + def perform(%{"op" => "fetch_data_for_activity", "activity_id" => activity_id}, _job) do activity = Activity.get_by_id(activity_id) Pleroma.Web.RichMedia.Helpers.perform(:fetch, activity) end diff --git a/lib/pleroma/workers/mailer.ex b/lib/pleroma/workers/mailer.ex index 8bf9952bc..1cce2ea03 100644 --- a/lib/pleroma/workers/mailer.ex +++ b/lib/pleroma/workers/mailer.ex @@ -8,10 +8,10 @@ defmodule Pleroma.Workers.Mailer do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "mailer", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "email", "encoded_email" => encoded_email, "config" => config}) do + def perform(%{"op" => "email", "encoded_email" => encoded_email, "config" => config}, _job) do email = encoded_email |> Base.decode64!() @@ -20,7 +20,7 @@ def perform(%{"op" => "email", "encoded_email" => encoded_email, "config" => con Pleroma.Emails.Mailer.deliver(email, config) end - def perform(%{"op" => "digest_email", "user_id" => user_id}) do + def perform(%{"op" => "digest_email", "user_id" => user_id}, _job) do user = User.get_by_id(user_id) Pleroma.DigestEmailWorker.perform(user) end diff --git a/lib/pleroma/workers/publisher.ex b/lib/pleroma/workers/publisher.ex index c890ffb79..0a9084589 100644 --- a/lib/pleroma/workers/publisher.ex +++ b/lib/pleroma/workers/publisher.ex @@ -9,15 +9,15 @@ defmodule Pleroma.Workers.Publisher do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "federator_outgoing", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "publish", "activity_id" => activity_id}) do + def perform(%{"op" => "publish", "activity_id" => activity_id}, _job) do activity = Activity.get_by_id(activity_id) Federator.perform(:publish, activity) end - def perform(%{"op" => "publish_one", "module" => module_name, "params" => params}) do + def perform(%{"op" => "publish_one", "module" => module_name, "params" => params}, _job) do Federator.perform(:publish_one, String.to_atom(module_name), params) end end diff --git a/lib/pleroma/workers/receiver.ex b/lib/pleroma/workers/receiver.ex index d3de95716..4ee270d74 100644 --- a/lib/pleroma/workers/receiver.ex +++ b/lib/pleroma/workers/receiver.ex @@ -8,14 +8,14 @@ defmodule Pleroma.Workers.Receiver do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "federator_incoming", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "incoming_doc", "body" => doc}) do + def perform(%{"op" => "incoming_doc", "body" => doc}, _job) do Federator.perform(:incoming_doc, doc) end - def perform(%{"op" => "incoming_ap_doc", "params" => params}) do + def perform(%{"op" => "incoming_ap_doc", "params" => params}, _job) do Federator.perform(:incoming_ap_doc, params) end end diff --git a/lib/pleroma/workers/scheduled_activity_worker.ex b/lib/pleroma/workers/scheduled_activity_worker.ex index a49834fd8..d9724c78a 100644 --- a/lib/pleroma/workers/scheduled_activity_worker.ex +++ b/lib/pleroma/workers/scheduled_activity_worker.ex @@ -6,10 +6,10 @@ defmodule Pleroma.Workers.ScheduledActivityWorker do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "scheduled_activities", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "execute", "activity_id" => activity_id}) do + def perform(%{"op" => "execute", "activity_id" => activity_id}, _job) do Pleroma.ScheduledActivityWorker.perform(:execute, activity_id) end end diff --git a/lib/pleroma/workers/subscriber.ex b/lib/pleroma/workers/subscriber.ex index 6af3ad0a1..783c44173 100644 --- a/lib/pleroma/workers/subscriber.ex +++ b/lib/pleroma/workers/subscriber.ex @@ -10,19 +10,19 @@ defmodule Pleroma.Workers.Subscriber do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "federator_outgoing", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "refresh_subscriptions"}) do + def perform(%{"op" => "refresh_subscriptions"}, _job) do Federator.perform(:refresh_subscriptions) end - def perform(%{"op" => "request_subscription", "websub_id" => websub_id}) do + def perform(%{"op" => "request_subscription", "websub_id" => websub_id}, _job) do websub = Repo.get(WebsubClientSubscription, websub_id) Federator.perform(:request_subscription, websub) end - def perform(%{"op" => "verify_websub", "websub_id" => websub_id}) do + def perform(%{"op" => "verify_websub", "websub_id" => websub_id}, _job) do websub = Repo.get(WebsubClientSubscription, websub_id) Federator.perform(:verify_websub, websub) end diff --git a/lib/pleroma/workers/transmogrifier.ex b/lib/pleroma/workers/transmogrifier.ex index c6b4fab47..e13202c06 100644 --- a/lib/pleroma/workers/transmogrifier.ex +++ b/lib/pleroma/workers/transmogrifier.ex @@ -8,10 +8,10 @@ defmodule Pleroma.Workers.Transmogrifier do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "transmogrifier", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "user_upgrade", "user_id" => user_id}) do + def perform(%{"op" => "user_upgrade", "user_id" => user_id}, _job) do user = User.get_by_id(user_id) Pleroma.Web.ActivityPub.Transmogrifier.perform(:user_upgrade, user) end diff --git a/lib/pleroma/workers/web_pusher.ex b/lib/pleroma/workers/web_pusher.ex index b99581eb0..7b78bb3ea 100644 --- a/lib/pleroma/workers/web_pusher.ex +++ b/lib/pleroma/workers/web_pusher.ex @@ -9,10 +9,10 @@ defmodule Pleroma.Workers.WebPusher do # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, queue: "web_push", - max_attempts: Pleroma.Config.get([:workers, :retries, :compile_time_default]) + max_attempts: 1 @impl Oban.Worker - def perform(%{"op" => "web_push", "notification_id" => notification_id}) do + def perform(%{"op" => "web_push", "notification_id" => notification_id}, _job) do notification = Repo.get(Notification, notification_id) Pleroma.Web.Push.Impl.perform(notification) end diff --git a/mix.exs b/mix.exs index b651520ed..eb023313d 100644 --- a/mix.exs +++ b/mix.exs @@ -101,7 +101,7 @@ defp deps do {:phoenix_ecto, "~> 4.0"}, {:ecto_sql, "~> 3.1"}, {:postgrex, ">= 0.13.5"}, - {:oban, "~> 0.6"}, + {:oban, "~> 0.7"}, {:gettext, "~> 0.15"}, {:comeonin, "~> 4.1.1"}, {:pbkdf2_elixir, "~> 0.12.3"}, diff --git a/mix.lock b/mix.lock index 52932c9ef..8b8596375 100644 --- a/mix.lock +++ b/mix.lock @@ -17,12 +17,12 @@ "credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "crontab": {:hex, :crontab, "1.1.7", "b9219f0bdc8678b94143655a8f229716c5810c0636a4489f98c0956137e53985", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, - "db_connection": {:hex, :db_connection, "2.0.6", "bde2f85d047969c5b5800cb8f4b3ed6316c8cb11487afedac4aa5f93fd39abfa", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, + "db_connection": {:hex, :db_connection, "2.1.1", "a51e8a2ee54ef2ae6ec41a668c85787ed40cb8944928c191280fe34c15b76ae5", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, "decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm"}, - "ecto": {:hex, :ecto, "3.1.4", "69d852da7a9f04ede725855a35ede48d158ca11a404fe94f8b2fb3b2162cd3c9", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, - "ecto_sql": {:hex, :ecto_sql, "3.1.3", "2c536139190492d9de33c5fefac7323c5eaaa82e1b9bf93482a14649042f7cd9", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, + "ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, + "ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"}, "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"}, "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, @@ -57,7 +57,7 @@ "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"}, - "oban": {:hex, :oban, "0.6.0", "8b9b861355610e703e58a878bc29959f3f0e1b4cd1e90d785cf2bb2498d3b893", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, + "oban": {:hex, :oban, "0.7.1", "171bdd1b69c1a4a839f8c768f5e962fc22d1de1513d459fb6b8e0cbd34817a9a", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"}, "phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, @@ -71,7 +71,7 @@ "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, - "postgrex": {:hex, :postgrex, "0.14.3", "5754dee2fdf6e9e508cbf49ab138df964278700b764177e8f3871e658b345a1e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, + "postgrex": {:hex, :postgrex, "0.15.0", "dd5349161019caeea93efa42f9b22f9d79995c3a86bdffb796427b4c9863b0f0", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.4.1", "1e96073b3ed7788053768fea779cbc896ddc3bdd9ba60687f2ad50b252ac87d6", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex index d379c9ec7..989770926 100644 --- a/test/support/oban_helpers.ex +++ b/test/support/oban_helpers.ex @@ -16,7 +16,7 @@ def perform_all do end def perform(%Oban.Job{} = job) do - res = apply(String.to_existing_atom("Elixir." <> job.worker), :perform, [job]) + res = apply(String.to_existing_atom("Elixir." <> job.worker), :perform, [job.args, job]) Repo.delete(job) res end From c056736daaedb2a08557ee6c6a9bcb6bf44110ca Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 23 Aug 2019 16:11:39 +0300 Subject: [PATCH 007/272] [#1149] Publisher worker fix (atomized `params` keys). --- lib/pleroma/workers/publisher.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/workers/publisher.ex b/lib/pleroma/workers/publisher.ex index 0a9084589..00fae99c7 100644 --- a/lib/pleroma/workers/publisher.ex +++ b/lib/pleroma/workers/publisher.ex @@ -18,6 +18,7 @@ def perform(%{"op" => "publish", "activity_id" => activity_id}, _job) do end def perform(%{"op" => "publish_one", "module" => module_name, "params" => params}, _job) do + params = Map.new(params, fn {k, v} -> {String.to_atom(k), v} end) Federator.perform(:publish_one, String.to_atom(module_name), params) end end From 581123f8bb703023cb652267a1fc34292f862852 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 23 Aug 2019 18:28:23 +0300 Subject: [PATCH 008/272] [#1149] Introduced `quantum` job scheduler. Documentation & config changes. --- CHANGELOG.md | 2 ++ config/config.exs | 40 +++++++++++++++++--------- config/test.exs | 2 -- docs/config.md | 15 ++++++---- lib/pleroma/application.ex | 19 ++---------- lib/pleroma/scheduler.ex | 7 +++++ lib/pleroma/web/federator/federator.ex | 8 +----- mix.exs | 2 +- mix.lock | 6 +++- 9 files changed, 54 insertions(+), 47 deletions(-) create mode 100644 lib/pleroma/scheduler.ex diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b0f4f40e..6dc19e79f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Unsubscribe followers when they unfollow a user - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) - Improve digest email template +- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) with [Oban](https://github.com/sorentwo/oban) +- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler ### Fixed - Not being able to pin unlisted posts diff --git a/config/config.exs b/config/config.exs index 1a6348bcd..43d114d70 100644 --- a/config/config.exs +++ b/config/config.exs @@ -51,6 +51,24 @@ telemetry_event: [Pleroma.Repo.Instrumenter], migration_lock: nil +scheduled_jobs = + with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], + true <- digest_config[:active] do + [{digest_config[:schedule], {Pleroma.DigestEmailWorker, :perform, []}}] + else + _ -> [] + end + +scheduled_jobs = + scheduled_jobs ++ + [{"0 */6 * * * *", {Pleroma.Web.Websub, :refresh_subscriptions, []}}] + +config :pleroma, Pleroma.Scheduler, + global: true, + overlap: true, + timezone: :utc, + jobs: scheduled_jobs + config :pleroma, Pleroma.Captcha, enabled: false, seconds_valid: 60, @@ -449,23 +467,19 @@ "web" ] -job_queues = [ - federator_incoming: 50, - federator_outgoing: 50, - web_push: 50, - mailer: 10, - transmogrifier: 20, - scheduled_activities: 10, - background: 5 -] - -config :pleroma_job_queue, :queues, job_queues - config :pleroma, Oban, repo: Pleroma.Repo, verbose: false, prune: {:maxage, 60 * 60 * 24 * 7}, - queues: job_queues + queues: [ + federator_incoming: 50, + federator_outgoing: 50, + web_push: 50, + mailer: 10, + transmogrifier: 20, + scheduled_activities: 10, + background: 5 + ] config :pleroma, :workers, retries: [ diff --git a/config/test.exs b/config/test.exs index a0fa67516..62f2a04d2 100644 --- a/config/test.exs +++ b/config/test.exs @@ -61,8 +61,6 @@ config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock -config :pleroma_job_queue, disabled: true - config :pleroma, Oban, queues: false, prune: :disabled diff --git a/docs/config.md b/docs/config.md index ae8afad89..81923c640 100644 --- a/docs/config.md +++ b/docs/config.md @@ -400,9 +400,9 @@ You can then do curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken" ``` -## :pleroma_job_queue +## Oban -[Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs. +[Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration. Pleroma has the following queues: @@ -416,12 +416,15 @@ Pleroma has the following queues: Example: ```elixir -config :pleroma_job_queue, :queues, - federator_incoming: 50, - federator_outgoing: 50 +config :pleroma, Oban, + repo: Pleroma.Repo, + queues: [ + federator_incoming: 50, + federator_outgoing: 50 + ] ``` -This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the `max_jobs` set to `50`. +This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the number of max concurrent jobs set to `50`. ## Pleroma.Web.Metadata * `providers`: a list of metadata providers to enable. Providers available: diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 384b03aa9..ce2d3ab59 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -31,6 +31,7 @@ def start(_type, _args) do children = [ Pleroma.Repo, + Pleroma.Scheduler, Pleroma.Config.TransferTask, Pleroma.Emoji, Pleroma.Captcha, @@ -69,9 +70,7 @@ def start(_type, _args) do # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html # for other strategies and supported options opts = [strategy: :one_for_one, name: Pleroma.Supervisor] - result = Supervisor.start_link(children, opts) - :ok = after_supervisor_start() - result + Supervisor.start_link(children, opts) end defp setup_instrumenters do @@ -162,18 +161,4 @@ defp hackney_pool_children do :hackney_pool.child_spec(pool, options) end end - - defp after_supervisor_start do - with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], - true <- digest_config[:active] do - # TODO: consider replacing with `quantum` scheduler - PleromaJobQueue.schedule( - digest_config[:schedule], - :digest_emails, - Pleroma.DigestEmailWorker - ) - end - - :ok - end end diff --git a/lib/pleroma/scheduler.ex b/lib/pleroma/scheduler.ex new file mode 100644 index 000000000..d84cd99ad --- /dev/null +++ b/lib/pleroma/scheduler.ex @@ -0,0 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Scheduler do + use Quantum.Scheduler, otp_app: :pleroma +end diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index d85fe824f..cf7e50fee 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Web.Federator do defdelegate worker_args(queue), to: Pleroma.Workers.Helper def init do - # 1 minute + # To do: consider removing this call in favor of scheduled execution (`quantum`-based) refresh_subscriptions(schedule_in: 60) end @@ -146,12 +146,6 @@ def perform(:verify_websub, websub) do def perform(:refresh_subscriptions) do Logger.debug("Federator running refresh subscriptions") Websub.refresh_subscriptions() - - spawn(fn -> - # 6 hours - Process.sleep(1000 * 60 * 60 * 6) - refresh_subscriptions() - end) end def ap_enabled_actor(id) do diff --git a/mix.exs b/mix.exs index eb023313d..9d8ded1ff 100644 --- a/mix.exs +++ b/mix.exs @@ -102,6 +102,7 @@ defp deps do {:ecto_sql, "~> 3.1"}, {:postgrex, ">= 0.13.5"}, {:oban, "~> 0.7"}, + {:quantum, "~> 2.3"}, {:gettext, "~> 0.15"}, {:comeonin, "~> 4.1.1"}, {:pbkdf2_elixir, "~> 0.12.3"}, @@ -142,7 +143,6 @@ defp deps do {:http_signatures, git: "https://git.pleroma.social/pleroma/http_signatures.git", ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"}, - {:pleroma_job_queue, "~> 0.3"}, {:telemetry, "~> 0.3"}, {:prometheus_ex, "~> 3.0"}, {:prometheus_plugs, "~> 1.1"}, diff --git a/mix.lock b/mix.lock index 8b8596375..6ebc66271 100644 --- a/mix.lock +++ b/mix.lock @@ -36,6 +36,8 @@ "excoveralls": {:hex, :excoveralls, "0.11.1", "dd677fbdd49114fdbdbf445540ec735808250d56b011077798316505064edb2c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "gen_smtp": {:hex, :gen_smtp, "0.14.0", "39846a03522456077c6429b4badfd1d55e5e7d0fdfb65e935b7c5e38549d9202", [:rebar3], [], "hexpm"}, + "gen_stage": {:hex, :gen_stage, "0.14.2", "6a2a578a510c5bfca8a45e6b27552f613b41cf584b58210f017088d3d17d0b14", [:mix], [], "hexpm"}, + "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"}, "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"}, @@ -46,6 +48,7 @@ "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "joken": {:hex, :joken, "2.0.1", "ec9ab31bf660f343380da033b3316855197c8d4c6ef597fa3fcb451b326beb14", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"}, "jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, + "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"}, "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm"}, @@ -65,7 +68,6 @@ "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"}, - "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.3.0", "b84538d621f0c3d6fcc1cff9d5648d3faaf873b8b21b94e6503428a07a48ec47", [:mix], [{:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}], "hexpm"}, "plug": {:hex, :plug, "1.8.2", "0bcce1daa420f189a6491f3940cc77ea7fb1919761175c9c3b59800d897440fc", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, @@ -78,9 +80,11 @@ "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"}, "quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm"}, + "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"}, "swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]}, From 71700ea6d4104ecd2cc0afb0ac103e722b30fbb5 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sat, 24 Aug 2019 09:27:32 +0300 Subject: [PATCH 009/272] [#1149] Updated docs & tests. --- docs/config.md | 6 ++++++ test/web/admin_api/admin_api_controller_test.exs | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/config.md b/docs/config.md index 81923c640..5b2c3a022 100644 --- a/docs/config.md +++ b/docs/config.md @@ -426,6 +426,12 @@ config :pleroma, Oban, This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the number of max concurrent jobs set to `50`. +## :workers + +Includes custom worker options not interpretable directly by `Oban`. + +* `retries` — keyword lists where keys are `Oban` queues (see above) and values are numbers of max attempts for failed jobs. + ## Pleroma.Web.Metadata * `providers`: a list of metadata providers to enable. Providers available: * Pleroma.Web.Metadata.Providers.OpenGraph diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 844cd0732..a867ac998 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1861,7 +1861,7 @@ test "queues key as atom", %{conn: conn} do post(conn, "/api/pleroma/admin/config", %{ configs: [ %{ - "group" => "pleroma_job_queue", + "group" => "oban", "key" => ":queues", "value" => [ %{"tuple" => [":federator_incoming", 50]}, @@ -1879,7 +1879,7 @@ test "queues key as atom", %{conn: conn} do assert json_response(conn, 200) == %{ "configs" => [ %{ - "group" => "pleroma_job_queue", + "group" => "oban", "key" => ":queues", "value" => [ %{"tuple" => [":federator_incoming", 50]}, From ef9930ed8050a309f2d95df8f0504de2b1da4677 Mon Sep 17 00:00:00 2001 From: ultem Date: Sat, 24 Aug 2019 10:16:27 +0000 Subject: [PATCH 010/272] Minor corrections and clarification for Alpine standard v.3.10 --- docs/installation/alpine_linux_en.md | 33 +++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/docs/installation/alpine_linux_en.md b/docs/installation/alpine_linux_en.md index 1f300f353..c77618936 100644 --- a/docs/installation/alpine_linux_en.md +++ b/docs/installation/alpine_linux_en.md @@ -1,7 +1,9 @@ # Installing on Alpine Linux ## Installation -This guide is a step-by-step installation guide for Alpine Linux. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/#configuration). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -l -s $SHELL -c 'command'` instead. +This guide is a step-by-step installation guide for Alpine Linux. The instructions were verified against Alpine v.3.10 standard image. You might miss additional dependencies if you use `netboot` instead. + +It assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/#configuration). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -l -s $SHELL -c 'command'` instead. ### Required packages @@ -20,12 +22,13 @@ This guide is a step-by-step installation guide for Alpine Linux. It also assume ### Prepare the system -* First make sure to have the community repository enabled: +* The community repository must be enabled in `/etc/apk/repositories`. Depending on which version and mirror you use this looks like `http://alpine.42.fr/v3.10/community`. If you autogenerated the mirror during installation: ```shell -echo "https://nl.alpinelinux.org/alpine/latest-stable/community" | sudo tee -a /etc/apk/repository +awk 'NR==2' /etc/apk/repositories | sed 's/main/community/' | tee -a /etc/apk/repositories ``` + * Then update the system, if not already done: ```shell @@ -77,7 +80,8 @@ sudo rc-update add postgresql * Add a new system user for the Pleroma service: ```shell -sudo adduser -S -s /bin/false -h /opt/pleroma -H pleroma +sudo addgroup pleroma +sudo adduser -S -s /bin/false -h /opt/pleroma -H -G pleroma pleroma ``` **Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell. @@ -164,7 +168,26 @@ If that doesn’t work, make sure, that nginx is not already running. If it stil sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf ``` -* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths) +* Before starting nginx edit the configuration and change it to your needs. You must change change `server_name` and the paths to the certificates. You can use `nano` (install with `apk add nano` if missing). + +``` +server { + server_name your.domain; + listen 80; + ... +} + +server { + server_name your.domain; + listen 443 ssl http2; + ... + ssl_trusted_certificate /etc/letsencrypt/live/your.domain/chain.pem; + ssl_certificate /etc/letsencrypt/live/your.domain/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/your.domain/privkey.pem; + ... +} +``` + * Enable and start nginx: ```shell From cd78e63a2528ab813088d5e44a026f6bb05b344b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 27 Aug 2019 14:34:37 +0300 Subject: [PATCH 011/272] [#1149] Bugfix: Pleroma.Workers.Subscriber / "verify_websub" works with WebsubServerSubscription. --- lib/pleroma/workers/subscriber.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/workers/subscriber.ex b/lib/pleroma/workers/subscriber.ex index 783c44173..e960b35bf 100644 --- a/lib/pleroma/workers/subscriber.ex +++ b/lib/pleroma/workers/subscriber.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Workers.Subscriber do alias Pleroma.Repo alias Pleroma.Web.Federator - alias Pleroma.Web.Websub.WebsubClientSubscription + alias Pleroma.Web.Websub # Note: `max_attempts` is intended to be overridden in `new/1` call use Oban.Worker, @@ -18,12 +18,12 @@ def perform(%{"op" => "refresh_subscriptions"}, _job) do end def perform(%{"op" => "request_subscription", "websub_id" => websub_id}, _job) do - websub = Repo.get(WebsubClientSubscription, websub_id) + websub = Repo.get(Websub.WebsubClientSubscription, websub_id) Federator.perform(:request_subscription, websub) end def perform(%{"op" => "verify_websub", "websub_id" => websub_id}, _job) do - websub = Repo.get(WebsubClientSubscription, websub_id) + websub = Repo.get(Websub.WebsubServerSubscription, websub_id) Federator.perform(:verify_websub, websub) end end From 5e4fde1d3d49ec56fae3b199fb4af51057e2dffd Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 27 Aug 2019 20:48:16 +0300 Subject: [PATCH 012/272] Filter logs by date --- lib/pleroma/moderation_log.ex | 37 ++++++++++++++- lib/pleroma/user/info.ex | 4 +- .../web/admin_api/admin_api_controller.ex | 8 +++- .../admin_api/admin_api_controller_test.exs | 46 +++++++++++++++++++ 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 1ef6fe67a..2164ecfc2 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -14,13 +14,46 @@ defmodule Pleroma.ModerationLog do timestamps() end - def get_all(page, page_size) do + def get_all(params) do + params + |> get_all_query() + |> maybe_filter_by_date(params) + |> Repo.all() + end + + defp maybe_filter_by_date(query, %{start_date: nil, end_date: nil}), do: query + + defp maybe_filter_by_date(query, %{start_date: start_date, end_date: nil}) do + from(q in query, + where: q.inserted_at >= ^parse_datetime(start_date) + ) + end + + defp maybe_filter_by_date(query, %{start_date: nil, end_date: end_date}) do + from(q in query, + where: q.inserted_at <= ^parse_datetime(end_date) + ) + end + + defp maybe_filter_by_date(query, %{start_date: start_date, end_date: end_date}) do + from(q in query, + where: q.inserted_at >= ^parse_datetime(start_date), + where: q.inserted_at <= ^parse_datetime(end_date) + ) + end + + defp get_all_query(%{page: page, page_size: page_size}) do from(q in __MODULE__, order_by: [desc: q.inserted_at], limit: ^page_size, offset: ^((page - 1) * page_size) ) - |> Repo.all() + end + + defp parse_datetime(datetime) do + {:ok, parsed_datetime, _} = DateTime.from_iso8601(datetime) + + parsed_datetime end def insert_log(%{ diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 779bfbc18..7027c947b 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -318,9 +318,7 @@ defp valid_field?(%{"name" => name, "value" => value}) do name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255) value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) - is_binary(name) && - is_binary(value) && - String.length(name) <= name_limit && + is_binary(name) && is_binary(value) && String.length(name) <= name_limit && String.length(value) <= value_limit end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 544b9d7d8..065394a24 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -539,7 +539,13 @@ def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do def list_log(conn, params) do {page, page_size} = page_params(params) - log = ModerationLog.get_all(page, page_size) + log = + ModerationLog.get_all(%{ + page: page, + page_size: page_size, + start_date: params["start_date"], + end_date: params["end_date"] + }) conn |> put_view(ModerationLogView) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 4e2c27431..a7269aee9 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -2348,6 +2348,52 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do assert second_entry["message"] == "@#{admin.nickname} followed relay: https://example.org/relay" end + + test "filters log by date", %{conn: conn, admin: admin} do + first_date = "2017-08-15T15:47:06Z" + second_date = "2017-08-20T15:47:06Z" + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_follow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.from_iso8601!(first_date) + }) + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_unfollow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.from_iso8601!(second_date) + }) + + conn1 = + get( + conn, + "/api/pleroma/admin/moderation_log?start_date=#{second_date}" + ) + + response1 = json_response(conn1, 200) + [first_entry] = response1 + + assert response1 |> length() == 1 + assert first_entry["data"]["action"] == "relay_unfollow" + + assert first_entry["message"] == + "@#{admin.nickname} unfollowed relay: https://example.org/relay" + end end end From cef2e980b1f6b07c2bdb01030559aca83257bd7e Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 28 Aug 2019 21:32:44 +0300 Subject: [PATCH 013/272] division emoji.ex on loader.ex and emoji.ex --- lib/mix/tasks/pleroma/emoji.ex | 2 +- lib/pleroma/emoji.ex | 212 +++------------------------------ lib/pleroma/emoji/loader.ex | 204 +++++++++++++++++++++++++++++++ test/emoji/loader_test.exs | 83 +++++++++++++ test/emoji_test.exs | 75 ------------ 5 files changed, 304 insertions(+), 272 deletions(-) create mode 100644 lib/pleroma/emoji/loader.ex create mode 100644 test/emoji/loader_test.exs diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index c2225af7d..dc5f7c193 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -235,7 +235,7 @@ def run(["gen-pack", src]) do cwd: tmp_pack_dir ) - emoji_map = Pleroma.Emoji.make_shortcode_to_file_map(tmp_pack_dir, exts) + emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts) File.write!(files_name, Jason.encode!(emoji_map, pretty: true)) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 66e20f0e4..ab6ba7d6a 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -4,24 +4,22 @@ defmodule Pleroma.Emoji do @moduledoc """ - The emojis are loaded from: - - * emoji packs in INSTANCE-DIR/emoji - * the files: `config/emoji.txt` and `config/custom_emoji.txt` - * glob paths, nested folder is used as tag name for grouping e.g. priv/static/emoji/custom/nested_folder - - This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime. + This GenServer stores in an ETS table the list of the loaded emojis, + and also allows to reload the list at runtime. """ use GenServer + alias Pleroma.Emoji.Loader + require Logger - @type pattern :: Regex.t() | module() | String.t() - @type patterns :: pattern() | [pattern()] - @type group_patterns :: keyword(patterns()) - @ets __MODULE__.Ets - @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}] + @ets_options [ + :ordered_set, + :protected, + :named_table, + {:read_concurrency, true} + ] @doc false def start_link(_) do @@ -44,7 +42,7 @@ def get(name) do end @doc "Returns all the emojos!!" - @spec get_all() :: [{String.t(), String.t()}, ...] + @spec get_all() :: list({String.t(), String.t(), String.t()}) def get_all do :ets.tab2list(@ets) end @@ -58,13 +56,13 @@ def init(_) do @doc false def handle_cast(:reload, state) do - load() + update_emojis(Loader.load()) {:noreply, state} end @doc false def handle_call(:reload, _from, state) do - load() + update_emojis(Loader.load()) {:reply, :ok, state} end @@ -75,189 +73,11 @@ def terminate(_, _) do @doc false def code_change(_old_vsn, state, _extra) do - load() + update_emojis(Loader.load()) {:ok, state} end - defp load do - emoji_dir_path = - Path.join( - Pleroma.Config.get!([:instance, :static_dir]), - "emoji" - ) - - emoji_groups = Pleroma.Config.get([:emoji, :groups]) - - case File.ls(emoji_dir_path) do - {:error, :enoent} -> - # The custom emoji directory doesn't exist, - # don't do anything - nil - - {:error, e} -> - # There was some other error - Logger.error("Could not access the custom emoji directory #{emoji_dir_path}: #{e}") - - {:ok, results} -> - grouped = - Enum.group_by(results, fn file -> File.dir?(Path.join(emoji_dir_path, file)) end) - - packs = grouped[true] || [] - files = grouped[false] || [] - - # Print the packs we've found - Logger.info("Found emoji packs: #{Enum.join(packs, ", ")}") - - if not Enum.empty?(files) do - Logger.warn( - "Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{ - Enum.join(files, ", ") - }" - ) - end - - emojis = - Enum.flat_map( - packs, - fn pack -> load_pack(Path.join(emoji_dir_path, pack), emoji_groups) end - ) - - true = :ets.insert(@ets, emojis) - end - - # Compat thing for old custom emoji handling & default emoji, - # it should run even if there are no emoji packs - shortcode_globs = Pleroma.Config.get([:emoji, :shortcode_globs], []) - - emojis = - (load_from_file("config/emoji.txt", emoji_groups) ++ - load_from_file("config/custom_emoji.txt", emoji_groups) ++ - load_from_globs(shortcode_globs, emoji_groups)) - |> Enum.reject(fn value -> value == nil end) - - true = :ets.insert(@ets, emojis) - - :ok - end - - defp load_pack(pack_dir, emoji_groups) do - pack_name = Path.basename(pack_dir) - - emoji_txt = Path.join(pack_dir, "emoji.txt") - - if File.exists?(emoji_txt) do - load_from_file(emoji_txt, emoji_groups) - else - extensions = Pleroma.Config.get([:emoji, :pack_extensions]) - - Logger.info( - "No emoji.txt found for pack \"#{pack_name}\", assuming all #{Enum.join(extensions, ", ")} files are emoji" - ) - - make_shortcode_to_file_map(pack_dir, extensions) - |> Enum.map(fn {shortcode, rel_file} -> - filename = Path.join("/emoji/#{pack_name}", rel_file) - - {shortcode, filename, [to_string(match_extra(emoji_groups, filename))]} - end) - end - end - - def make_shortcode_to_file_map(pack_dir, exts) do - find_all_emoji(pack_dir, exts) - |> Enum.map(&Path.relative_to(&1, pack_dir)) - |> Enum.map(fn f -> {f |> Path.basename() |> Path.rootname(), f} end) - |> Enum.into(%{}) - end - - def find_all_emoji(dir, exts) do - Enum.reduce( - File.ls!(dir), - [], - fn f, acc -> - filepath = Path.join(dir, f) - - if File.dir?(filepath) do - acc ++ find_all_emoji(filepath, exts) - else - acc ++ [filepath] - end - end - ) - |> Enum.filter(fn f -> Path.extname(f) in exts end) - end - - defp load_from_file(file, emoji_groups) do - if File.exists?(file) do - load_from_file_stream(File.stream!(file), emoji_groups) - else - [] - end - end - - defp load_from_file_stream(stream, emoji_groups) do - stream - |> Stream.map(&String.trim/1) - |> Stream.map(fn line -> - case String.split(line, ~r/,\s*/) do - [name, file] -> - {name, file, [to_string(match_extra(emoji_groups, file))]} - - [name, file | tags] -> - {name, file, tags} - - _ -> - nil - end - end) - |> Enum.to_list() - end - - defp load_from_globs(globs, emoji_groups) do - static_path = Path.join(:code.priv_dir(:pleroma), "static") - - paths = - Enum.map(globs, fn glob -> - Path.join(static_path, glob) - |> Path.wildcard() - end) - |> Enum.concat() - - Enum.map(paths, fn path -> - tag = match_extra(emoji_groups, Path.join("/", Path.relative_to(path, static_path))) - shortcode = Path.basename(path, Path.extname(path)) - external_path = Path.join("/", Path.relative_to(path, static_path)) - {shortcode, external_path, [to_string(tag)]} - end) - end - - @doc """ - Finds a matching group for the given emoji filename - """ - @spec match_extra(group_patterns(), String.t()) :: atom() | nil - def match_extra(group_patterns, filename) do - match_group_patterns(group_patterns, fn pattern -> - case pattern do - %Regex{} = regex -> Regex.match?(regex, filename) - string when is_binary(string) -> filename == string - end - end) - end - - defp match_group_patterns(group_patterns, matcher) do - Enum.find_value(group_patterns, fn {group, patterns} -> - patterns = - patterns - |> List.wrap() - |> Enum.map(fn pattern -> - if String.contains?(pattern, "*") do - ~r(#{String.replace(pattern, "*", ".*")}) - else - pattern - end - end) - - Enum.any?(patterns, matcher) && group - end) + defp update_emojis(emojis) do + :ets.insert(@ets, emojis) end end diff --git a/lib/pleroma/emoji/loader.ex b/lib/pleroma/emoji/loader.ex new file mode 100644 index 000000000..e93b0aecc --- /dev/null +++ b/lib/pleroma/emoji/loader.ex @@ -0,0 +1,204 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.Loader do + @moduledoc """ + The Loader emoji from: + + * emoji packs in INSTANCE-DIR/emoji + * the files: `config/emoji.txt` and `config/custom_emoji.txt` + * glob paths, nested folder is used as tag name for grouping e.g. priv/static/emoji/custom/nested_folder + """ + alias Pleroma.Config + + require Logger + + @type pattern :: Regex.t() | module() | String.t() + @type patterns :: pattern() | [pattern()] + @type group_patterns :: keyword(patterns()) + @type emoji :: {String.t(), String.t(), list(String.t())} + + @doc """ + Loads emojis from files/packs. + + returns list emojis in format: + `{"000", "/emoji/freespeechextremist.com/000.png", ["Custom"]}` + """ + @spec load() :: list(emoji) + def load do + emoji_dir_path = Path.join(Config.get!([:instance, :static_dir]), "emoji") + + emoji_groups = Config.get([:emoji, :groups]) + + emojis = + case File.ls(emoji_dir_path) do + {:error, :enoent} -> + # The custom emoji directory doesn't exist, + # don't do anything + [] + + {:error, e} -> + # There was some other error + Logger.error("Could not access the custom emoji directory #{emoji_dir_path}: #{e}") + [] + + {:ok, results} -> + grouped = + Enum.group_by(results, fn file -> + File.dir?(Path.join(emoji_dir_path, file)) + end) + + packs = grouped[true] || [] + files = grouped[false] || [] + + # Print the packs we've found + Logger.info("Found emoji packs: #{Enum.join(packs, ", ")}") + + if not Enum.empty?(files) do + Logger.warn( + "Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{ + Enum.join(files, ", ") + }" + ) + end + + Enum.flat_map(packs, fn pack -> + load_pack(Path.join(emoji_dir_path, pack), emoji_groups) + end) + end + + # Compat thing for old custom emoji handling & default emoji, + # it should run even if there are no emoji packs + shortcode_globs = Config.get([:emoji, :shortcode_globs], []) + + emojis_txt = + (load_from_file("config/emoji.txt", emoji_groups) ++ + load_from_file("config/custom_emoji.txt", emoji_groups) ++ + load_from_globs(shortcode_globs, emoji_groups)) + |> Enum.reject(fn value -> value == nil end) + + emojis ++ emojis_txt + end + + defp load_pack(pack_dir, emoji_groups) do + pack_name = Path.basename(pack_dir) + + emoji_txt = Path.join(pack_dir, "emoji.txt") + + if File.exists?(emoji_txt) do + load_from_file(emoji_txt, emoji_groups) + else + extensions = Config.get([:emoji, :pack_extensions]) + + Logger.info( + "No emoji.txt found for pack \"#{pack_name}\", assuming all #{Enum.join(extensions, ", ")} files are emoji" + ) + + make_shortcode_to_file_map(pack_dir, extensions) + |> Enum.map(fn {shortcode, rel_file} -> + filename = Path.join("/emoji/#{pack_name}", rel_file) + + {shortcode, filename, [to_string(match_extra(emoji_groups, filename))]} + end) + end + end + + def make_shortcode_to_file_map(pack_dir, exts) do + find_all_emoji(pack_dir, exts) + |> Enum.map(&Path.relative_to(&1, pack_dir)) + |> Enum.map(fn f -> {f |> Path.basename() |> Path.rootname(), f} end) + |> Enum.into(%{}) + end + + def find_all_emoji(dir, exts) do + Enum.reduce( + File.ls!(dir), + [], + fn f, acc -> + filepath = Path.join(dir, f) + + if File.dir?(filepath) do + acc ++ find_all_emoji(filepath, exts) + else + acc ++ [filepath] + end + end + ) + |> Enum.filter(fn f -> Path.extname(f) in exts end) + end + + defp load_from_file(file, emoji_groups) do + if File.exists?(file) do + load_from_file_stream(File.stream!(file), emoji_groups) + else + [] + end + end + + defp load_from_file_stream(stream, emoji_groups) do + stream + |> Stream.map(&String.trim/1) + |> Stream.map(fn line -> + case String.split(line, ~r/,\s*/) do + [name, file] -> + {name, file, [to_string(match_extra(emoji_groups, file))]} + + [name, file | tags] -> + {name, file, tags} + + _ -> + nil + end + end) + |> Enum.to_list() + end + + defp load_from_globs(globs, emoji_groups) do + static_path = Path.join(:code.priv_dir(:pleroma), "static") + + paths = + Enum.map(globs, fn glob -> + Path.join(static_path, glob) + |> Path.wildcard() + end) + |> Enum.concat() + + Enum.map(paths, fn path -> + tag = match_extra(emoji_groups, Path.join("/", Path.relative_to(path, static_path))) + shortcode = Path.basename(path, Path.extname(path)) + external_path = Path.join("/", Path.relative_to(path, static_path)) + {shortcode, external_path, [to_string(tag)]} + end) + end + + @doc """ + Finds a matching group for the given emoji filename + """ + @spec match_extra(group_patterns(), String.t()) :: atom() | nil + def match_extra(group_patterns, filename) do + match_group_patterns(group_patterns, fn pattern -> + case pattern do + %Regex{} = regex -> Regex.match?(regex, filename) + string when is_binary(string) -> filename == string + end + end) + end + + defp match_group_patterns(group_patterns, matcher) do + Enum.find_value(group_patterns, fn {group, patterns} -> + patterns = + patterns + |> List.wrap() + |> Enum.map(fn pattern -> + if String.contains?(pattern, "*") do + ~r(#{String.replace(pattern, "*", ".*")}) + else + pattern + end + end) + + Enum.any?(patterns, matcher) && group + end) + end +end diff --git a/test/emoji/loader_test.exs b/test/emoji/loader_test.exs new file mode 100644 index 000000000..045eef150 --- /dev/null +++ b/test/emoji/loader_test.exs @@ -0,0 +1,83 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.LoaderTest do + use ExUnit.Case, async: true + alias Pleroma.Emoji.Loader + + describe "match_extra/2" do + setup do + groups = [ + "list of files": ["/emoji/custom/first_file.png", "/emoji/custom/second_file.png"], + "wildcard folder": "/emoji/custom/*/file.png", + "wildcard files": "/emoji/custom/folder/*.png", + "special file": "/emoji/custom/special.png" + ] + + {:ok, groups: groups} + end + + test "config for list of files", %{groups: groups} do + group = + groups + |> Loader.match_extra("/emoji/custom/first_file.png") + |> to_string() + + assert group == "list of files" + end + + test "config with wildcard folder", %{groups: groups} do + group = + groups + |> Loader.match_extra("/emoji/custom/some_folder/file.png") + |> to_string() + + assert group == "wildcard folder" + end + + test "config with wildcard folder and subfolders", %{groups: groups} do + group = + groups + |> Loader.match_extra("/emoji/custom/some_folder/another_folder/file.png") + |> to_string() + + assert group == "wildcard folder" + end + + test "config with wildcard files", %{groups: groups} do + group = + groups + |> Loader.match_extra("/emoji/custom/folder/some_file.png") + |> to_string() + + assert group == "wildcard files" + end + + test "config with wildcard files and subfolders", %{groups: groups} do + group = + groups + |> Loader.match_extra("/emoji/custom/folder/another_folder/some_file.png") + |> to_string() + + assert group == "wildcard files" + end + + test "config for special file", %{groups: groups} do + group = + groups + |> Loader.match_extra("/emoji/custom/special.png") + |> to_string() + + assert group == "special file" + end + + test "no mathing returns nil", %{groups: groups} do + group = + groups + |> Loader.match_extra("/emoji/some_undefined.png") + + refute group + end + end +end diff --git a/test/emoji_test.exs b/test/emoji_test.exs index 07ac6ff1d..32a828cc9 100644 --- a/test/emoji_test.exs +++ b/test/emoji_test.exs @@ -32,79 +32,4 @@ test "random emoji", %{emoji_list: emoji_list} do assert is_list(tags) end end - - describe "match_extra/2" do - setup do - groups = [ - "list of files": ["/emoji/custom/first_file.png", "/emoji/custom/second_file.png"], - "wildcard folder": "/emoji/custom/*/file.png", - "wildcard files": "/emoji/custom/folder/*.png", - "special file": "/emoji/custom/special.png" - ] - - {:ok, groups: groups} - end - - test "config for list of files", %{groups: groups} do - group = - groups - |> Emoji.match_extra("/emoji/custom/first_file.png") - |> to_string() - - assert group == "list of files" - end - - test "config with wildcard folder", %{groups: groups} do - group = - groups - |> Emoji.match_extra("/emoji/custom/some_folder/file.png") - |> to_string() - - assert group == "wildcard folder" - end - - test "config with wildcard folder and subfolders", %{groups: groups} do - group = - groups - |> Emoji.match_extra("/emoji/custom/some_folder/another_folder/file.png") - |> to_string() - - assert group == "wildcard folder" - end - - test "config with wildcard files", %{groups: groups} do - group = - groups - |> Emoji.match_extra("/emoji/custom/folder/some_file.png") - |> to_string() - - assert group == "wildcard files" - end - - test "config with wildcard files and subfolders", %{groups: groups} do - group = - groups - |> Emoji.match_extra("/emoji/custom/folder/another_folder/some_file.png") - |> to_string() - - assert group == "wildcard files" - end - - test "config for special file", %{groups: groups} do - group = - groups - |> Emoji.match_extra("/emoji/custom/special.png") - |> to_string() - - assert group == "special file" - end - - test "no mathing returns nil", %{groups: groups} do - group = - groups - |> Emoji.match_extra("/emoji/some_undefined.png") - - refute group - end - end end From d7808b5db437b3300122127cef4c7ad076de7bda Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 29 Aug 2019 06:22:18 +0300 Subject: [PATCH 014/272] added code\path fields without html tags in ets --- lib/pleroma/emoji/loader.ex | 12 +- lib/pleroma/formatter.ex | 31 ++--- lib/pleroma/web/common_api/utils.ex | 2 +- .../controllers/mastodon_api_controller.ex | 2 +- .../controllers/util_controller.ex | 2 +- test/emoji_test.exs | 8 +- test/formatter_test.exs | 110 +++++++++--------- 7 files changed, 93 insertions(+), 74 deletions(-) diff --git a/lib/pleroma/emoji/loader.ex b/lib/pleroma/emoji/loader.ex index e93b0aecc..70eba9ac6 100644 --- a/lib/pleroma/emoji/loader.ex +++ b/lib/pleroma/emoji/loader.ex @@ -78,7 +78,17 @@ def load do load_from_globs(shortcode_globs, emoji_groups)) |> Enum.reject(fn value -> value == nil end) - emojis ++ emojis_txt + Enum.map(emojis ++ emojis_txt, &prepare_emoji/1) + end + + defp prepare_emoji({code, file, tags} = _emoji) do + { + code, + file, + tags, + Pleroma.HTML.strip_tags(code), + Pleroma.HTML.strip_tags(file) + } end defp load_pack(pack_dir, emoji_groups) do diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 607843a5b..84955289c 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -107,19 +107,22 @@ def emojify(text) do def emojify(text, nil), do: text def emojify(text, emoji, strip \\ false) do - Enum.reduce(emoji, text, fn emoji_data, text -> - emoji = HTML.strip_tags(elem(emoji_data, 0)) - file = HTML.strip_tags(elem(emoji_data, 1)) + Enum.reduce(emoji, text, fn + {_, _, _, emoji, file}, text -> + String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) - html = - if not strip do - "#{emoji}" - else - "" - end - - String.replace(text, ":#{emoji}:", html) |> HTML.filter_tags() + emoji_data, text -> + emoji = HTML.strip_tags(elem(emoji_data, 0)) + file = HTML.strip_tags(elem(emoji_data, 1)) + String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) end) + |> HTML.filter_tags() + end + + defp prepare_emoji_html(_emoji, _file, true), do: "" + + defp prepare_emoji_html(emoji, file, _strip) do + "#{emoji}" end def demojify(text) do @@ -130,7 +133,9 @@ def demojify(text, nil), do: text @doc "Outputs a list of the emoji-shortcodes in a text" def get_emoji(text) when is_binary(text) do - Enum.filter(Emoji.get_all(), fn {emoji, _, _} -> String.contains?(text, ":#{emoji}:") end) + Enum.filter(Emoji.get_all(), fn {emoji, _, _, _, _} -> + String.contains?(text, ":#{emoji}:") + end) end def get_emoji(_), do: [] @@ -138,7 +143,7 @@ def get_emoji(_), do: [] @doc "Outputs a list of the emoji-Maps in a text" def get_emoji_map(text) when is_binary(text) do get_emoji(text) - |> Enum.reduce(%{}, fn {name, file, _group}, acc -> + |> Enum.reduce(%{}, fn {name, file, _group, _, _}, acc -> Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") end) end diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 6958c7511..9686e6491 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -435,7 +435,7 @@ def confirm_current_password(user, password) do def emoji_from_profile(%{info: _info} = user) do (Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name)) - |> Enum.map(fn {shortcode, url, _} -> + |> Enum.map(fn {shortcode, url, _, _, _} -> %{ "type" => "Emoji", "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"}, diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 83e877c0e..603c6b3c6 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -331,7 +331,7 @@ def peers(conn, _params) do defp mastodonized_emoji do Pleroma.Emoji.get_all() - |> Enum.map(fn {shortcode, relative_url, tags} -> + |> Enum.map(fn {shortcode, relative_url, tags, _, _} -> url = to_string(URI.merge(Web.base_url(), relative_url)) %{ diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 3405bd3b7..923480242 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -240,7 +240,7 @@ def version(conn, _params) do def emoji(conn, _params) do emoji = Emoji.get_all() - |> Enum.map(fn {short_code, path, tags} -> + |> Enum.map(fn {short_code, path, tags, _, _} -> {short_code, %{image_url: path, tags: tags}} end) |> Enum.into(%{}) diff --git a/test/emoji_test.exs b/test/emoji_test.exs index 32a828cc9..82f9c52ff 100644 --- a/test/emoji_test.exs +++ b/test/emoji_test.exs @@ -14,9 +14,9 @@ defmodule Pleroma.EmojiTest do test "first emoji", %{emoji_list: emoji_list} do [emoji | _others] = emoji_list - {code, path, tags} = emoji + {code, path, tags, _, _} = emoji - assert tuple_size(emoji) == 3 + assert tuple_size(emoji) == 5 assert is_binary(code) assert is_binary(path) assert is_list(tags) @@ -24,9 +24,9 @@ test "first emoji", %{emoji_list: emoji_list} do test "random emoji", %{emoji_list: emoji_list} do emoji = Enum.random(emoji_list) - {code, path, tags} = emoji + {code, path, tags, _, _} = emoji - assert tuple_size(emoji) == 3 + assert tuple_size(emoji) == 5 assert is_binary(code) assert is_binary(path) assert is_list(tags) diff --git a/test/formatter_test.exs b/test/formatter_test.exs index bfa673049..7a5bd0f9f 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -217,6 +217,27 @@ test "given the 'safe_mention' option, it will keep text after newlines" do assert expected_text =~ "how are you doing?" end + + test "it can parse mentions and return the relevant users" do + text = + "@@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme@archae.me and @o and @@@jimm" + + o = insert(:user, %{nickname: "o"}) + jimm = insert(:user, %{nickname: "jimm"}) + gsimg = insert(:user, %{nickname: "gsimg"}) + archaeme = insert(:user, %{nickname: "archaeme"}) + archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"}) + + expected_mentions = [ + {"@archaeme", archaeme}, + {"@archaeme@archae.me", archaeme_remote}, + {"@gsimg", gsimg}, + {"@jimm", jimm}, + {"@o", o} + ] + + assert {_text, ^expected_mentions, []} = Formatter.linkify(text) + end end describe ".parse_tags" do @@ -234,67 +255,50 @@ test "parses tags in the text" do end end - test "it can parse mentions and return the relevant users" do - text = - "@@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme@archae.me and @o and @@@jimm" + describe "emojify" do + test "it adds cool emoji" do + text = "I love :firefox:" - o = insert(:user, %{nickname: "o"}) - jimm = insert(:user, %{nickname: "jimm"}) - gsimg = insert(:user, %{nickname: "gsimg"}) - archaeme = insert(:user, %{nickname: "archaeme"}) - archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"}) + expected_result = + "I love \"firefox\"" - expected_mentions = [ - {"@archaeme", archaeme}, - {"@archaeme@archae.me", archaeme_remote}, - {"@gsimg", gsimg}, - {"@jimm", jimm}, - {"@o", o} - ] + assert Formatter.emojify(text) == expected_result + end - assert {_text, ^expected_mentions, []} = Formatter.linkify(text) + test "it does not add XSS emoji" do + text = + "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" + + custom_emoji = %{ + "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)" => + "https://placehold.it/1x1" + } + + expected_result = + "I love \"\"" + + assert Formatter.emojify(text, custom_emoji) == expected_result + end end - test "it adds cool emoji" do - text = "I love :firefox:" + describe "get_emoji" do + test "it returns the emoji used in the text" do + text = "I love :firefox:" - expected_result = - "I love \"firefox\"" + assert Formatter.get_emoji(text) == [ + {"firefox", "/emoji/Firefox.gif", ["Gif", "Fun"], "firefox", "/emoji/Firefox.gif"} + ] + end - assert Formatter.emojify(text) == expected_result - end + test "it returns a nice empty result when no emojis are present" do + text = "I love moominamma" + assert Formatter.get_emoji(text) == [] + end - test "it does not add XSS emoji" do - text = - "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" - - custom_emoji = %{ - "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)" => - "https://placehold.it/1x1" - } - - expected_result = - "I love \"\"" - - assert Formatter.emojify(text, custom_emoji) == expected_result - end - - test "it returns the emoji used in the text" do - text = "I love :firefox:" - - assert Formatter.get_emoji(text) == [ - {"firefox", "/emoji/Firefox.gif", ["Gif", "Fun"]} - ] - end - - test "it returns a nice empty result when no emojis are present" do - text = "I love moominamma" - assert Formatter.get_emoji(text) == [] - end - - test "it doesn't die when text is absent" do - text = nil - assert Formatter.get_emoji(text) == [] + test "it doesn't die when text is absent" do + text = nil + assert Formatter.get_emoji(text) == [] + end end test "it escapes HTML in plain text" do From 5c90b7073332ac333a5db9dfc82744cee03843fa Mon Sep 17 00:00:00 2001 From: Maksim Date: Thu, 29 Aug 2019 11:45:25 +0000 Subject: [PATCH 015/272] Apply suggestion to lib/pleroma/emoji/loader.ex --- lib/pleroma/emoji/loader.ex | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/pleroma/emoji/loader.ex b/lib/pleroma/emoji/loader.ex index 70eba9ac6..82fc3b8c3 100644 --- a/lib/pleroma/emoji/loader.ex +++ b/lib/pleroma/emoji/loader.ex @@ -122,19 +122,17 @@ def make_shortcode_to_file_map(pack_dir, exts) do end def find_all_emoji(dir, exts) do - Enum.reduce( - File.ls!(dir), - [], - fn f, acc -> - filepath = Path.join(dir, f) + dir + |> File.ls!() + |> Enum.flat_map(fn f -> + filepath = Path.join(dir, f) - if File.dir?(filepath) do - acc ++ find_all_emoji(filepath, exts) - else - acc ++ [filepath] - end + if File.dir?(filepath) do + find_all_emoji(filepath, exts) + else + [filepath] end - ) + end) |> Enum.filter(fn f -> Path.extname(f) in exts end) end From d8098d142a0e8412eabdf5fe63705c25bcb1be34 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 29 Aug 2019 22:01:37 +0300 Subject: [PATCH 016/272] added Emoji.Formatter --- lib/pleroma/emoji/formatter.ex | 59 +++++++++++++++++++ lib/pleroma/formatter.ex | 52 ---------------- lib/pleroma/web/common_api/common_api.ex | 18 +++--- lib/pleroma/web/common_api/utils.ex | 5 +- .../controllers/mastodon_api_controller.ex | 4 +- lib/pleroma/web/metadata/utils.ex | 5 +- .../web/twitter_api/twitter_api_controller.ex | 4 +- .../web/twitter_api/views/activity_view.ex | 6 +- .../web/twitter_api/views/user_view.ex | 7 ++- test/emoji/formatter_test.exs | 54 +++++++++++++++++ test/formatter_test.exs | 46 --------------- 11 files changed, 141 insertions(+), 119 deletions(-) create mode 100644 lib/pleroma/emoji/formatter.ex create mode 100644 test/emoji/formatter_test.exs diff --git a/lib/pleroma/emoji/formatter.ex b/lib/pleroma/emoji/formatter.ex new file mode 100644 index 000000000..acdef3988 --- /dev/null +++ b/lib/pleroma/emoji/formatter.ex @@ -0,0 +1,59 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.Formatter do + alias Pleroma.Emoji + alias Pleroma.HTML + alias Pleroma.Web.MediaProxy + + def emojify(text) do + emojify(text, Emoji.get_all()) + end + + def emojify(text, nil), do: text + + def emojify(text, emoji, strip \\ false) do + Enum.reduce(emoji, text, fn + {_, _, _, emoji, file}, text -> + String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) + + emoji_data, text -> + emoji = HTML.strip_tags(elem(emoji_data, 0)) + file = HTML.strip_tags(elem(emoji_data, 1)) + String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) + end) + |> HTML.filter_tags() + end + + defp prepare_emoji_html(_emoji, _file, true), do: "" + + defp prepare_emoji_html(emoji, file, _strip) do + "#{emoji}" + end + + def demojify(text) do + emojify(text, Emoji.get_all(), true) + end + + def demojify(text, nil), do: text + + @doc "Outputs a list of the emoji-shortcodes in a text" + def get_emoji(text) when is_binary(text) do + Enum.filter(Emoji.get_all(), fn {emoji, _, _, _, _} -> + String.contains?(text, ":#{emoji}:") + end) + end + + def get_emoji(_), do: [] + + @doc "Outputs a list of the emoji-Maps in a text" + def get_emoji_map(text) when is_binary(text) do + get_emoji(text) + |> Enum.reduce(%{}, fn {name, file, _group, _, _}, acc -> + Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") + end) + end + + def get_emoji_map(_), do: [] +end diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 84955289c..dbbfe3a66 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -3,10 +3,8 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Formatter do - alias Pleroma.Emoji alias Pleroma.HTML alias Pleroma.User - alias Pleroma.Web.MediaProxy @safe_mention_regex ~r/^(\s*(?(@.+?\s+){1,})+)(?.*)/s @link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui @@ -100,56 +98,6 @@ def mentions_escape(text, options \\ []) do end end - def emojify(text) do - emojify(text, Emoji.get_all()) - end - - def emojify(text, nil), do: text - - def emojify(text, emoji, strip \\ false) do - Enum.reduce(emoji, text, fn - {_, _, _, emoji, file}, text -> - String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) - - emoji_data, text -> - emoji = HTML.strip_tags(elem(emoji_data, 0)) - file = HTML.strip_tags(elem(emoji_data, 1)) - String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) - end) - |> HTML.filter_tags() - end - - defp prepare_emoji_html(_emoji, _file, true), do: "" - - defp prepare_emoji_html(emoji, file, _strip) do - "#{emoji}" - end - - def demojify(text) do - emojify(text, Emoji.get_all(), true) - end - - def demojify(text, nil), do: text - - @doc "Outputs a list of the emoji-shortcodes in a text" - def get_emoji(text) when is_binary(text) do - Enum.filter(Emoji.get_all(), fn {emoji, _, _, _, _} -> - String.contains?(text, ":#{emoji}:") - end) - end - - def get_emoji(_), do: [] - - @doc "Outputs a list of the emoji-Maps in a text" - def get_emoji_map(text) when is_binary(text) do - get_emoji(text) - |> Enum.reduce(%{}, fn {name, file, _group, _, _}, acc -> - Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") - end) - end - - def get_emoji_map(_), do: [] - def html_escape({text, mentions, hashtags}, type) do {html_escape(text, type), mentions, hashtags} end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 5faddc9f4..9ee704022 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.CommonAPI do alias Pleroma.Activity alias Pleroma.ActivityExpiration alias Pleroma.Conversation.Participation - alias Pleroma.Formatter + alias Pleroma.Emoji alias Pleroma.Object alias Pleroma.ThreadMute alias Pleroma.User @@ -261,12 +261,7 @@ def post(user, %{"status" => status} = data) do sensitive, poll ), - object <- - Map.put( - object, - "emoji", - Map.merge(Formatter.get_emoji_map(full_payload), poll_emoji) - ) do + object <- put_emoji(object, full_payload, poll_emoji) do preview? = Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false direct? = visibility == "direct" @@ -300,6 +295,15 @@ def post(user, %{"status" => status} = data) do end end + # parse and put emoji to object data + defp put_emoji(map, text, emojis) do + Map.put( + map, + "emoji", + Map.merge(Emoji.Formatter.get_emoji_map(text), emojis) + ) + end + # Updates the emojis for a user based on their profile def update(user) do user = diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 9686e6491..d6907f707 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Conversation.Participation + alias Pleroma.Emoji alias Pleroma.Formatter alias Pleroma.Object alias Pleroma.Plugs.AuthenticationPlug @@ -184,7 +185,7 @@ def make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_i "name" => option, "type" => "Note", "replies" => %{"type" => "Collection", "totalItems" => 0} - }, Map.merge(emoji, Formatter.get_emoji_map(option))} + }, Map.merge(emoji, Emoji.Formatter.get_emoji_map(option))} end) case expires_in do @@ -434,7 +435,7 @@ def confirm_current_password(user, password) do end def emoji_from_profile(%{info: _info} = user) do - (Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name)) + (Emoji.Formatter.get_emoji(user.bio) ++ Emoji.Formatter.get_emoji(user.name)) |> Enum.map(fn {shortcode, url, _, _, _} -> %{ "type" => "Emoji", diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 603c6b3c6..4f63b03cf 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -13,8 +13,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Bookmark alias Pleroma.Config alias Pleroma.Conversation.Participation + alias Pleroma.Emoji alias Pleroma.Filter - alias Pleroma.Formatter alias Pleroma.HTTP alias Pleroma.Notification alias Pleroma.Object @@ -140,7 +140,7 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do user_info_emojis = user.info |> Map.get(:emoji, []) - |> Enum.concat(Formatter.get_emoji_map(emojis_text)) + |> Enum.concat(Emoji.Formatter.get_emoji_map(emojis_text)) |> Enum.dedup() info_params = diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index 720bd4519..382ecf426 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.Utils do + alias Pleroma.Emoji alias Pleroma.Formatter alias Pleroma.HTML alias Pleroma.Web.MediaProxy @@ -13,7 +14,7 @@ def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do |> HtmlEntities.decode() |> String.replace(~r//, " ") |> HTML.get_cached_stripped_html_for_activity(object, "metadata") - |> Formatter.demojify() + |> Emoji.Formatter.demojify() |> Formatter.truncate() end @@ -23,7 +24,7 @@ def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) |> HtmlEntities.decode() |> String.replace(~r//, " ") |> HTML.strip_tags() - |> Formatter.demojify() + |> Emoji.Formatter.demojify() |> Formatter.truncate(max_length) end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 5dfab6a6c..4141bfba5 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do alias Ecto.Changeset alias Pleroma.Activity - alias Pleroma.Formatter + alias Pleroma.Emoji alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo @@ -713,7 +713,7 @@ defp parse_profile_bio(user, params) do emojis_text = (params["description"] || "") <> " " <> (params["name"] || "") emojis = - ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text)) + ((user.info.emoji || []) ++ Emoji.Formatter.get_emoji_map(emojis_text)) |> Enum.dedup() user_info = diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index abae63877..9192ebd34 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do use Pleroma.Web, :view alias Pleroma.Activity - alias Pleroma.Formatter + alias Pleroma.Emoji alias Pleroma.HTML alias Pleroma.Object alias Pleroma.Repo @@ -262,7 +262,7 @@ def render( activity, "twitterapi:content" ) - |> Formatter.emojify(object.data["emoji"]) + |> Emoji.Formatter.emojify(object.data["emoji"]) text = if content do @@ -319,7 +319,7 @@ def render( "possibly_sensitive" => possibly_sensitive, "visibility" => Pleroma.Web.ActivityPub.Visibility.get_visibility(object), "summary" => summary, - "summary_html" => summary |> Formatter.emojify(object.data["emoji"]), + "summary_html" => Emoji.Formatter.emojify(summary, object.data["emoji"]), "card" => card, "muted" => thread_muted? || User.mutes?(opts[:for], user) } diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 8a7d2fc72..3a6550826 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -4,7 +4,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do use Pleroma.Web, :view - alias Pleroma.Formatter + + alias Pleroma.Emoji alias Pleroma.HTML alias Pleroma.User alias Pleroma.Web.CommonAPI.Utils @@ -72,7 +73,7 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do description_html = (user.bio || "") |> HTML.filter_tags(User.html_filter_policy(for_user)) - |> Formatter.emojify(emoji) + |> Emoji.Formatter.emojify(emoji) fields = user.info @@ -99,7 +100,7 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do "name" => user.name || user.nickname, "name_html" => if(user.name, - do: HTML.strip_tags(user.name) |> Formatter.emojify(emoji), + do: HTML.strip_tags(user.name) |> Emoji.Formatter.emojify(emoji), else: user.nickname ), "profile_image_url" => image, diff --git a/test/emoji/formatter_test.exs b/test/emoji/formatter_test.exs new file mode 100644 index 000000000..8b510f48b --- /dev/null +++ b/test/emoji/formatter_test.exs @@ -0,0 +1,54 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.FormatterTest do + alias Pleroma.Emoji.Formatter + use Pleroma.DataCase + + describe "emojify" do + test "it adds cool emoji" do + text = "I love :firefox:" + + expected_result = + "I love \"firefox\"" + + assert Formatter.emojify(text) == expected_result + end + + test "it does not add XSS emoji" do + text = + "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" + + custom_emoji = %{ + "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)" => + "https://placehold.it/1x1" + } + + expected_result = + "I love \"\"" + + assert Formatter.emojify(text, custom_emoji) == expected_result + end + end + + describe "get_emoji" do + test "it returns the emoji used in the text" do + text = "I love :firefox:" + + assert Formatter.get_emoji(text) == [ + {"firefox", "/emoji/Firefox.gif", ["Gif", "Fun"], "firefox", "/emoji/Firefox.gif"} + ] + end + + test "it returns a nice empty result when no emojis are present" do + text = "I love moominamma" + assert Formatter.get_emoji(text) == [] + end + + test "it doesn't die when text is absent" do + text = nil + assert Formatter.get_emoji(text) == [] + end + end +end diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 7a5bd0f9f..c36681068 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -255,52 +255,6 @@ test "parses tags in the text" do end end - describe "emojify" do - test "it adds cool emoji" do - text = "I love :firefox:" - - expected_result = - "I love \"firefox\"" - - assert Formatter.emojify(text) == expected_result - end - - test "it does not add XSS emoji" do - text = - "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" - - custom_emoji = %{ - "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)" => - "https://placehold.it/1x1" - } - - expected_result = - "I love \"\"" - - assert Formatter.emojify(text, custom_emoji) == expected_result - end - end - - describe "get_emoji" do - test "it returns the emoji used in the text" do - text = "I love :firefox:" - - assert Formatter.get_emoji(text) == [ - {"firefox", "/emoji/Firefox.gif", ["Gif", "Fun"], "firefox", "/emoji/Firefox.gif"} - ] - end - - test "it returns a nice empty result when no emojis are present" do - text = "I love moominamma" - assert Formatter.get_emoji(text) == [] - end - - test "it doesn't die when text is absent" do - text = nil - assert Formatter.get_emoji(text) == [] - end - end - test "it escapes HTML in plain text" do text = "hello & world google.com/?a=b&c=d \n http://test.com/?a=b&c=d 1" expected = "hello & world google.com/?a=b&c=d \n http://test.com/?a=b&c=d 1" From 880307e0d52444326eee8e79b2f66af706d85b4a Mon Sep 17 00:00:00 2001 From: ultem Date: Fri, 30 Aug 2019 19:41:31 +0000 Subject: [PATCH 017/272] minor: Fix version dot --- docs/installation/alpine_linux_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/alpine_linux_en.md b/docs/installation/alpine_linux_en.md index c77618936..f200362ca 100644 --- a/docs/installation/alpine_linux_en.md +++ b/docs/installation/alpine_linux_en.md @@ -1,7 +1,7 @@ # Installing on Alpine Linux ## Installation -This guide is a step-by-step installation guide for Alpine Linux. The instructions were verified against Alpine v.3.10 standard image. You might miss additional dependencies if you use `netboot` instead. +This guide is a step-by-step installation guide for Alpine Linux. The instructions were verified against Alpine v3.10 standard image. You might miss additional dependencies if you use `netboot` instead. It assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/#configuration). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -l -s $SHELL -c 'command'` instead. From f182f0f6bd89a2f2e3c4a6000c772512b239fe54 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sat, 31 Aug 2019 00:57:15 +0300 Subject: [PATCH 018/272] Add ability to search moderation logs --- lib/pleroma/moderation_log.ex | 209 ++++++++++++------ .../web/admin_api/admin_api_controller.ex | 4 +- test/moderation_log_test.exs | 36 ++- .../admin_api/admin_api_controller_test.exs | 61 ++++- 4 files changed, 220 insertions(+), 90 deletions(-) diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 2164ecfc2..c72a413b6 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -18,6 +18,8 @@ def get_all(params) do params |> get_all_query() |> maybe_filter_by_date(params) + |> maybe_filter_by_user(params) + |> maybe_filter_by_search(params) |> Repo.all() end @@ -42,6 +44,23 @@ defp maybe_filter_by_date(query, %{start_date: start_date, end_date: end_date}) ) end + defp maybe_filter_by_user(query, %{user_id: nil}), do: query + + defp maybe_filter_by_user(query, %{user_id: user_id}) do + from(q in query, + where: fragment("(?)->'actor'->>'id' = ?", q.data, ^user_id) + ) + end + + defp maybe_filter_by_search(query, %{search: search}) when is_nil(search) or search == "", + do: query + + defp maybe_filter_by_search(query, %{search: search}) do + from(q in query, + where: fragment("(?)->>'message' ILIKE ?", q.data, ^"%#{search}%") + ) + end + defp get_all_query(%{page: page, page_size: page_size}) do from(q in __MODULE__, order_by: [desc: q.inserted_at], @@ -56,52 +75,71 @@ defp parse_datetime(datetime) do parsed_datetime end + @spec insert_log(%{actor: User, subject: User, action: String.t(), permission: String.t()}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, subject: %User{} = subject, action: action, permission: permission }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - subject: user_to_map(subject), - action: action, - permission: permission + "actor" => user_to_map(actor), + "subject" => user_to_map(subject), + "action" => action, + "permission" => permission, + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{actor: User, subject: User, action: String.t()}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, action: "report_update", subject: %Activity{data: %{"type" => "Flag"}} = subject }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: "report_update", - subject: report_to_map(subject) + "actor" => user_to_map(actor), + "action" => "report_update", + "subject" => report_to_map(subject), + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{actor: User, subject: Activity, action: String.t(), text: String.t()}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, action: "report_response", subject: %Activity{} = subject, text: text }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: "report_response", - subject: report_to_map(subject), - text: text + "actor" => user_to_map(actor), + "action" => "report_response", + "subject" => report_to_map(subject), + "text" => text, + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{ + actor: User, + subject: Activity, + action: String.t(), + sensitive: String.t(), + visibility: String.t() + }) :: {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, action: "status_update", @@ -109,41 +147,49 @@ def insert_log(%{ sensitive: sensitive, visibility: visibility }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: "status_update", - subject: status_to_map(subject), - sensitive: sensitive, - visibility: visibility + "actor" => user_to_map(actor), + "action" => "status_update", + "subject" => status_to_map(subject), + "sensitive" => sensitive, + "visibility" => visibility, + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{actor: User, action: String.t(), subject_id: String.t()}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, action: "status_delete", subject_id: subject_id }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: "status_delete", - subject_id: subject_id + "actor" => user_to_map(actor), + "action" => "status_delete", + "subject_id" => subject_id, + "message" => "" } - }) + } + |> insert_log_entry_with_message() end @spec insert_log(%{actor: User, subject: User, action: String.t()}) :: {:ok, ModerationLog} | {:error, any} def insert_log(%{actor: %User{} = actor, subject: subject, action: action}) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: action, - subject: user_to_map(subject) + "actor" => user_to_map(actor), + "action" => action, + "subject" => user_to_map(subject), + "message" => "" } - }) + } + |> insert_log_entry_with_message() end @spec insert_log(%{actor: User, subjects: [User], action: String.t()}) :: @@ -151,97 +197,124 @@ def insert_log(%{actor: %User{} = actor, subject: subject, action: action}) do def insert_log(%{actor: %User{} = actor, subjects: subjects, action: action}) do subjects = Enum.map(subjects, &user_to_map/1) - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: action, - subjects: subjects + "actor" => user_to_map(actor), + "action" => action, + "subjects" => subjects, + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, followed: %User{} = followed, follower: %User{} = follower, action: "follow" }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: "follow", - followed: user_to_map(followed), - follower: user_to_map(follower) + "actor" => user_to_map(actor), + "action" => "follow", + "followed" => user_to_map(followed), + "follower" => user_to_map(follower), + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, followed: %User{} = followed, follower: %User{} = follower, action: "unfollow" }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: "unfollow", - followed: user_to_map(followed), - follower: user_to_map(follower) + "actor" => user_to_map(actor), + "action" => "unfollow", + "followed" => user_to_map(followed), + "follower" => user_to_map(follower), + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{actor: User, action: String.t(), nicknames: [String.t()], tags: [String.t()]}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, nicknames: nicknames, tags: tags, action: action }) do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - nicknames: nicknames, - tags: tags, - action: action + "actor" => user_to_map(actor), + "nicknames" => nicknames, + "tags" => tags, + "action" => action, + "message" => "" } - }) + } + |> insert_log_entry_with_message() end + @spec insert_log(%{actor: User, action: String.t(), target: String.t()}) :: + {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, action: action, target: target }) when action in ["relay_follow", "relay_unfollow"] do - Repo.insert(%ModerationLog{ + %ModerationLog{ data: %{ - actor: user_to_map(actor), - action: action, - target: target + "actor" => user_to_map(actor), + "action" => action, + "target" => target, + "message" => "" } - }) + } + |> insert_log_entry_with_message() + end + + @spec insert_log_entry_with_message(ModerationLog) :: {:ok, ModerationLog} | {:error, any} + + defp insert_log_entry_with_message(entry) do + entry.data["message"] + |> put_in(get_log_entry_message(entry)) + |> Repo.insert() end defp user_to_map(%User{} = user) do user |> Map.from_struct() |> Map.take([:id, :nickname]) - |> Map.put(:type, "user") + |> Map.new(fn {k, v} -> {Atom.to_string(k), v} end) + |> Map.put("type", "user") end defp report_to_map(%Activity{} = report) do %{ - type: "report", - id: report.id, - state: report.data["state"] + "type" => "report", + "id" => report.id, + "state" => report.data["state"] } end defp status_to_map(%Activity{} = status) do %{ - type: "status", - id: status.id + "type" => "status", + "id" => status.id } end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 065394a24..135c6ae87 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -544,7 +544,9 @@ def list_log(conn, params) do page: page, page_size: page_size, start_date: params["start_date"], - end_date: params["end_date"] + end_date: params["end_date"], + user_id: params["user_id"], + search: params["search"] }) conn diff --git a/test/moderation_log_test.exs b/test/moderation_log_test.exs index c78708471..a39a00e02 100644 --- a/test/moderation_log_test.exs +++ b/test/moderation_log_test.exs @@ -30,8 +30,7 @@ test "logging user deletion by moderator", %{moderator: moderator, subject1: sub log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == - "@#{moderator.nickname} deleted user @#{subject1.nickname}" + assert log.data["message"] == "@#{moderator.nickname} deleted user @#{subject1.nickname}" end test "logging user creation by moderator", %{ @@ -48,7 +47,7 @@ test "logging user creation by moderator", %{ log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} created users: @#{subject1.nickname}, @#{subject2.nickname}" end @@ -63,7 +62,7 @@ test "logging user follow by admin", %{admin: admin, subject1: subject1, subject log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{admin.nickname} made @#{subject2.nickname} follow @#{subject1.nickname}" end @@ -78,7 +77,7 @@ test "logging user unfollow by admin", %{admin: admin, subject1: subject1, subje log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{admin.nickname} made @#{subject2.nickname} unfollow @#{subject1.nickname}" end @@ -100,8 +99,7 @@ test "logging user tagged by admin", %{admin: admin, subject1: subject1, subject tags = ["foo", "bar"] |> Enum.join(", ") - assert ModerationLog.get_log_entry_message(log) == - "@#{admin.nickname} added tags: #{tags} to users: #{users}" + assert log.data["message"] == "@#{admin.nickname} added tags: #{tags} to users: #{users}" end test "logging user untagged by admin", %{admin: admin, subject1: subject1, subject2: subject2} do @@ -122,7 +120,7 @@ test "logging user untagged by admin", %{admin: admin, subject1: subject1, subje tags = ["foo", "bar"] |> Enum.join(", ") - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{admin.nickname} removed tags: #{tags} from users: #{users}" end @@ -137,8 +135,7 @@ test "logging user grant by moderator", %{moderator: moderator, subject1: subjec log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == - "@#{moderator.nickname} made @#{subject1.nickname} moderator" + assert log.data["message"] == "@#{moderator.nickname} made @#{subject1.nickname} moderator" end test "logging user revoke by moderator", %{moderator: moderator, subject1: subject1} do @@ -152,7 +149,7 @@ test "logging user revoke by moderator", %{moderator: moderator, subject1: subje log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} revoked moderator role from @#{subject1.nickname}" end @@ -166,7 +163,7 @@ test "logging relay follow", %{moderator: moderator} do log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} followed relay: https://example.org/relay" end @@ -180,7 +177,7 @@ test "logging relay unfollow", %{moderator: moderator} do log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} unfollowed relay: https://example.org/relay" end @@ -202,7 +199,7 @@ test "logging report update", %{moderator: moderator} do log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} updated report ##{report.id} with 'resolved' state" end @@ -224,7 +221,7 @@ test "logging report response", %{moderator: moderator} do log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} responded with 'look at this' to report ##{report.id}" end @@ -242,7 +239,7 @@ test "logging status sensitivity update", %{moderator: moderator} do log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true'" end @@ -260,7 +257,7 @@ test "logging status visibility update", %{moderator: moderator} do log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} updated status ##{note.id}, set visibility: 'private'" end @@ -278,7 +275,7 @@ test "logging status sensitivity & visibility update", %{moderator: moderator} d log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == + assert log.data["message"] == "@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true', visibility: 'private'" end @@ -294,8 +291,7 @@ test "logging status deletion", %{moderator: moderator} do log = Repo.one(ModerationLog) - assert ModerationLog.get_log_entry_message(log) == - "@#{moderator.nickname} deleted status ##{note.id}" + assert log.data["message"] == "@#{moderator.nickname} deleted status ##{note.id}" end end end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index a7269aee9..eaf847b25 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -2251,8 +2251,9 @@ test "returns private statuses with godmode on", %{conn: conn, user: user} do describe "GET /api/pleroma/admin/moderation_log" do setup %{conn: conn} do admin = insert(:user, info: %{is_admin: true}) + moderator = insert(:user, info: %{is_moderator: true}) - %{conn: assign(conn, :user, admin), admin: admin} + %{conn: assign(conn, :user, admin), admin: admin, moderator: moderator} end test "returns the log", %{conn: conn, admin: admin} do @@ -2394,6 +2395,64 @@ test "filters log by date", %{conn: conn, admin: admin} do assert first_entry["message"] == "@#{admin.nickname} unfollowed relay: https://example.org/relay" end + + test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_follow", + target: "https://example.org/relay" + } + }) + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => moderator.id, + "nickname" => moderator.nickname, + "type" => "user" + }, + action: "relay_unfollow", + target: "https://example.org/relay" + } + }) + + conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}") + + response1 = json_response(conn1, 200) + [first_entry] = response1 + + assert response1 |> length() == 1 + assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id + end + + test "returns log filtered by search", %{conn: conn, moderator: moderator} do + ModerationLog.insert_log(%{ + actor: moderator, + action: "relay_follow", + target: "https://example.org/relay" + }) + + ModerationLog.insert_log(%{ + actor: moderator, + action: "relay_unfollow", + target: "https://example.org/relay" + }) + + conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo") + + response1 = json_response(conn1, 200) + [first_entry] = response1 + + assert response1 |> length() == 1 + + assert get_in(first_entry, ["data", "message"]) == + "@#{moderator.nickname} unfollowed relay: https://example.org/relay" + end end end From 4d6e22bb9b718846883e92851ba22e9809b6b93d Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sat, 31 Aug 2019 01:09:48 +0300 Subject: [PATCH 019/272] Style --- lib/pleroma/moderation_log.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index c72a413b6..89a5e13c3 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -248,8 +248,12 @@ def insert_log(%{ |> insert_log_entry_with_message() end - @spec insert_log(%{actor: User, action: String.t(), nicknames: [String.t()], tags: [String.t()]}) :: - {:ok, ModerationLog} | {:error, any} + @spec insert_log(%{ + actor: User, + action: String.t(), + nicknames: [String.t()], + tags: [String.t()] + }) :: {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, nicknames: nicknames, From 6ef0103ca0b194971a2e6f61685316536b742a11 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Sat, 31 Aug 2019 10:14:53 +0300 Subject: [PATCH 020/272] added Emoji struct --- lib/pleroma/emoji.ex | 15 ++++++++++++++ lib/pleroma/emoji/formatter.ex | 12 +++++------ lib/pleroma/emoji/loader.ex | 13 +++--------- lib/pleroma/web/common_api/utils.ex | 2 +- .../controllers/mastodon_api_controller.ex | 2 +- .../controllers/util_controller.ex | 6 ++---- test/emoji/formatter_test.exs | 20 ++++++++++++++----- test/emoji_test.exs | 8 ++++---- 8 files changed, 47 insertions(+), 31 deletions(-) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index ab6ba7d6a..b246bfbe6 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -21,6 +21,21 @@ defmodule Pleroma.Emoji do {:read_concurrency, true} ] + defstruct [:code, :file, :tags, :safe_code, :safe_file] + + @doc "Build emoji struct" + def build({code, file, tags}) do + %__MODULE__{ + code: code, + file: file, + tags: tags, + safe_code: Pleroma.HTML.strip_tags(code), + safe_file: Pleroma.HTML.strip_tags(file) + } + end + + def build({code, file}), do: build({code, file, []}) + @doc false def start_link(_) do GenServer.start_link(__MODULE__, [], name: __MODULE__) diff --git a/lib/pleroma/emoji/formatter.ex b/lib/pleroma/emoji/formatter.ex index acdef3988..4869d073e 100644 --- a/lib/pleroma/emoji/formatter.ex +++ b/lib/pleroma/emoji/formatter.ex @@ -15,12 +15,12 @@ def emojify(text, nil), do: text def emojify(text, emoji, strip \\ false) do Enum.reduce(emoji, text, fn - {_, _, _, emoji, file}, text -> + {_, %Emoji{safe_code: emoji, safe_file: file}}, text -> String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) - emoji_data, text -> - emoji = HTML.strip_tags(elem(emoji_data, 0)) - file = HTML.strip_tags(elem(emoji_data, 1)) + {unsafe_emoji, unsafe_file}, text -> + emoji = HTML.strip_tags(unsafe_emoji) + file = HTML.strip_tags(unsafe_file) String.replace(text, ":#{emoji}:", prepare_emoji_html(emoji, file, strip)) end) |> HTML.filter_tags() @@ -40,7 +40,7 @@ def demojify(text, nil), do: text @doc "Outputs a list of the emoji-shortcodes in a text" def get_emoji(text) when is_binary(text) do - Enum.filter(Emoji.get_all(), fn {emoji, _, _, _, _} -> + Enum.filter(Emoji.get_all(), fn {emoji, %Emoji{}} -> String.contains?(text, ":#{emoji}:") end) end @@ -50,7 +50,7 @@ def get_emoji(_), do: [] @doc "Outputs a list of the emoji-Maps in a text" def get_emoji_map(text) when is_binary(text) do get_emoji(text) - |> Enum.reduce(%{}, fn {name, file, _group, _, _}, acc -> + |> Enum.reduce(%{}, fn {name, %Emoji{file: file}}, acc -> Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") end) end diff --git a/lib/pleroma/emoji/loader.ex b/lib/pleroma/emoji/loader.ex index 82fc3b8c3..839316713 100644 --- a/lib/pleroma/emoji/loader.ex +++ b/lib/pleroma/emoji/loader.ex @@ -11,13 +11,14 @@ defmodule Pleroma.Emoji.Loader do * glob paths, nested folder is used as tag name for grouping e.g. priv/static/emoji/custom/nested_folder """ alias Pleroma.Config + alias Pleroma.Emoji require Logger @type pattern :: Regex.t() | module() | String.t() @type patterns :: pattern() | [pattern()] @type group_patterns :: keyword(patterns()) - @type emoji :: {String.t(), String.t(), list(String.t())} + @type emoji :: {String.t(), Emoji.t()} @doc """ Loads emojis from files/packs. @@ -81,15 +82,7 @@ def load do Enum.map(emojis ++ emojis_txt, &prepare_emoji/1) end - defp prepare_emoji({code, file, tags} = _emoji) do - { - code, - file, - tags, - Pleroma.HTML.strip_tags(code), - Pleroma.HTML.strip_tags(file) - } - end + defp prepare_emoji({code, _, _} = emoji), do: {code, Emoji.build(emoji)} defp load_pack(pack_dir, emoji_groups) do pack_name = Path.basename(pack_dir) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index d6907f707..1fb95f4ab 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -436,7 +436,7 @@ def confirm_current_password(user, password) do def emoji_from_profile(%{info: _info} = user) do (Emoji.Formatter.get_emoji(user.bio) ++ Emoji.Formatter.get_emoji(user.name)) - |> Enum.map(fn {shortcode, url, _, _, _} -> + |> Enum.map(fn {shortcode, %Emoji{file: url}} -> %{ "type" => "Emoji", "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"}, diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 4f63b03cf..a50c060bf 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -331,7 +331,7 @@ def peers(conn, _params) do defp mastodonized_emoji do Pleroma.Emoji.get_all() - |> Enum.map(fn {shortcode, relative_url, tags, _, _} -> + |> Enum.map(fn {shortcode, %Pleroma.Emoji{file: relative_url, tags: tags}} -> url = to_string(URI.merge(Web.base_url(), relative_url)) %{ diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 923480242..c14792068 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -239,11 +239,9 @@ def version(conn, _params) do def emoji(conn, _params) do emoji = - Emoji.get_all() - |> Enum.map(fn {short_code, path, tags, _, _} -> - {short_code, %{image_url: path, tags: tags}} + Enum.reduce(Emoji.get_all(), %{}, fn {code, %Emoji{file: file, tags: tags}}, acc -> + Map.put(acc, code, %{image_url: file, tags: tags}) end) - |> Enum.into(%{}) json(conn, emoji) end diff --git a/test/emoji/formatter_test.exs b/test/emoji/formatter_test.exs index 8b510f48b..6d25fc453 100644 --- a/test/emoji/formatter_test.exs +++ b/test/emoji/formatter_test.exs @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emoji.FormatterTest do + alias Pleroma.Emoji alias Pleroma.Emoji.Formatter use Pleroma.DataCase @@ -20,15 +21,17 @@ test "it does not add XSS emoji" do text = "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" - custom_emoji = %{ - "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)" => + custom_emoji = + { + "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)", "https://placehold.it/1x1" - } + } + |> Pleroma.Emoji.build() expected_result = "I love \"\"" - assert Formatter.emojify(text, custom_emoji) == expected_result + assert Formatter.emojify(text, [{custom_emoji.code, custom_emoji}]) == expected_result end end @@ -37,7 +40,14 @@ test "it returns the emoji used in the text" do text = "I love :firefox:" assert Formatter.get_emoji(text) == [ - {"firefox", "/emoji/Firefox.gif", ["Gif", "Fun"], "firefox", "/emoji/Firefox.gif"} + {"firefox", + %Emoji{ + code: "firefox", + file: "/emoji/Firefox.gif", + tags: ["Gif", "Fun"], + safe_code: "firefox", + safe_file: "/emoji/Firefox.gif" + }} ] end diff --git a/test/emoji_test.exs b/test/emoji_test.exs index 82f9c52ff..1fdbd0fdf 100644 --- a/test/emoji_test.exs +++ b/test/emoji_test.exs @@ -14,9 +14,9 @@ defmodule Pleroma.EmojiTest do test "first emoji", %{emoji_list: emoji_list} do [emoji | _others] = emoji_list - {code, path, tags, _, _} = emoji + {code, %Emoji{file: path, tags: tags}} = emoji - assert tuple_size(emoji) == 5 + assert tuple_size(emoji) == 2 assert is_binary(code) assert is_binary(path) assert is_list(tags) @@ -24,9 +24,9 @@ test "first emoji", %{emoji_list: emoji_list} do test "random emoji", %{emoji_list: emoji_list} do emoji = Enum.random(emoji_list) - {code, path, tags, _, _} = emoji + {code, %Emoji{file: path, tags: tags}} = emoji - assert tuple_size(emoji) == 5 + assert tuple_size(emoji) == 2 assert is_binary(code) assert is_binary(path) assert is_list(tags) From 7808eee9aa4a02c289173a45e0b02def3bf51773 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Sat, 31 Aug 2019 16:23:15 +0900 Subject: [PATCH 021/272] Update Japanese document to follow English document --- docs/installation/debian_based_jp.md | 141 +++++++++++++-------------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/docs/installation/debian_based_jp.md b/docs/installation/debian_based_jp.md index caf72363b..5ca6b3634 100644 --- a/docs/installation/debian_based_jp.md +++ b/docs/installation/debian_based_jp.md @@ -5,180 +5,179 @@ ## インストール -このガイドはDebian Stretchを仮定しています。Ubuntu 16.04でも可能です。 +このガイドはDebian Stretchを利用することを想定しています。Ubuntu 16.04や18.04でもおそらく動作します。また、ユーザはrootもしくはsudoにより管理者権限を持っていることを前提とします。もし、以下の操作をrootユーザで行う場合は、 `sudo` を無視してください。ただし、`sudo -Hu pleroma` のようにユーザを指定している場合には `su -s $SHELL -c 'command'` を代わりに使ってください。 ### 必要なソフトウェア -- PostgreSQL 9.6+ (postgresql-contrib-9.6 または他のバージョンの PSQL をインストールしてください) -- Elixir 1.5 以上 ([Debianのリポジトリからインストールしないこと!!! ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like))。または [asdf](https://github.com/asdf-vm/asdf) を pleroma ユーザーでインストール。 -- erlang-dev +- 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 (Jessieではバックポートからインストールすること!) +- erlang-xmerl - git - build-essential -- openssh -- openssl -- nginx prefered (Apacheも動くかもしれませんが、誰もテストしていません!) -- certbot (または何らかのACME Let's encryptクライアント) + +#### このガイドで利用している追加パッケージ + +- nginx (おすすめです。他のリバースプロキシを使う場合は、参考となる設定をこのリポジトリから探してください) +- certbot (または何らかのLet's Encrypt向けACMEクライアント) ### システムを準備する * まずシステムをアップデートしてください。 ``` -apt update && apt dist-upgrade +sudo apt update +sudo apt full-upgrade ``` -* 複数のツールとpostgresqlをインストールします。あとで必要になるので。 +* 上記に挙げたパッケージをインストールしておきます。 ``` -apt install git build-essential openssl ssh sudo postgresql-9.6 postgresql-contrib-9.6 +sudo apt install git build-essential postgresql postgresql-contrib ``` -(postgresqlのバージョンは、あなたのディストロにあわせて変えてください。または、バージョン番号がいらないかもしれません。) + ### ElixirとErlangをインストールします * Erlangのリポジトリをダウンロードおよびインストールします。 ``` -wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb +wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb +sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb ``` * ElixirとErlangをインストールします、 ``` -apt update && apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh +sudo apt update +sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh ``` ### Pleroma BE (バックエンド) をインストールします -* 新しいユーザーを作ります。 -``` -adduser pleroma -``` -(Give it any password you want, make it STRONG) +* Pleroma用に新しいユーザーを作ります。 -* 新しいユーザーをsudoグループに入れます。 ``` -usermod -aG sudo pleroma +sudo useradd -r -s /bin/false -m -d /var/lib/pleroma -U pleroma ``` -* 新しいユーザーに変身し、ホームディレクトリに移動します。 -``` -su pleroma -cd ~ -``` +**注意**: Pleromaユーザとして単発のコマンドを実行したい場合はは、`sudo -Hu pleroma command` を使ってください。シェルを使いたい場合は `sudo -Hu pleroma $SHELL`です。もし `sudo` を使わない場合は、rootユーザで `su -l pleroma -s $SHELL -c 'command'` とすることでコマンドを、`su -l pleroma -s $SHELL` とすることでシェルを開始できます。 * Gitリポジトリをクローンします。 ``` -git clone -b master https://git.pleroma.social/pleroma/pleroma +sudo mkdir -p /opt/pleroma +sudo chown -R pleroma:pleroma /opt/pleroma +sudo -Hu pleroma git clone -b master https://git.pleroma.social/pleroma/pleroma /opt/pleroma ``` * 新しいディレクトリに移動します。 ``` -cd pleroma/ +cd /opt/pleroma ``` * Pleromaが依存するパッケージをインストールします。Hexをインストールしてもよいか聞かれたら、yesを入力してください。 ``` -mix deps.get +sudo -Hu pleroma mix deps.get ``` * コンフィギュレーションを生成します。 ``` -mix pleroma.instance gen +sudo -Hu pleroma mix pleroma.instance gen ``` * rebar3をインストールしてもよいか聞かれたら、yesを入力してください。 - * この処理には時間がかかります。私もよく分かりませんが、何らかのコンパイルが行われているようです。 - * あなたのインスタンスについて、いくつかの質問があります。その回答は `config/generated_config.exs` というコンフィギュレーションファイルに保存されます。 + * このときにpleromaの一部がコンパイルされるため、この処理には時間がかかります。 + * あなたのインスタンスについて、いくつかの質問されます。この質問により `config/generated_config.exs` という設定ファイルが生成されます。 -**注意**: メディアプロクシを有効にすると回答して、なおかつ、キャッシュのURLは空欄のままにしている場合は、`generated_config.exs` を編集して、`base_url` で始まる行をコメントアウトまたは削除してください。そして、上にある行の `true` の後にあるコンマを消してください。 * コンフィギュレーションを確認して、もし問題なければ、ファイル名を変更してください。 ``` mv config/{generated_config.exs,prod.secret.exs} ``` -* これまでのコマンドで、すでに `config/setup_db.psql` というファイルが作られています。このファイルをもとに、データベースを作成します。 +* 先程のコマンドで、すでに `config/setup_db.psql` というファイルが作られています。このファイルをもとに、データベースを作成します。 ``` -sudo su postgres -c 'psql -f config/setup_db.psql' +sudo -Hu pleroma mix pleroma.instance gen ``` -* そして、データベースのミグレーションを実行します。 +* そして、データベースのマイグレーションを実行します。 ``` -MIX_ENV=prod mix ecto.migrate +sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate ``` -* Pleromaを起動できるようになりました。 +* これでPleromaを起動できるようになりました。 ``` -MIX_ENV=prod mix phx.server +sudo -Hu pleroma MIX_ENV=prod mix phx.server ``` -### インストールを終わらせる +### インストールの最終段階 -あなたの新しいインスタンスを世界に向けて公開するには、nginxまたは何らかのウェブサーバー (プロクシ) を使用する必要があります。また、Pleroma のためにシステムサービスファイルを作成する必要があります。 +あなたの新しいインスタンスを世界に向けて公開するには、nginx等のWebサーバやプロキシサーバをPleromaの前段に使用する必要があります。また、Pleroma のためにシステムサービスファイルを作成する必要があります。 #### Nginx * まだインストールしていないなら、nginxをインストールします。 ``` -apt install nginx +sudo apt install nginx ``` * SSLをセットアップします。他の方法でもよいですが、ここではcertbotを説明します。 certbotを使うならば、まずそれをインストールします。 ``` -apt install certbot +sudo apt install certbot ``` そしてセットアップします。 ``` -mkdir -p /var/lib/letsencrypt/.well-known -% certbot certonly --email your@emailaddress --webroot -w /var/lib/letsencrypt/ -d yourdomain +sudo mkdir -p /var/lib/letsencrypt/ +sudo certbot certonly --email -d --standalone ``` -もしうまくいかないときは、先にnginxを設定してください。ssl "on" を "off" に変えてから再試行してください。 +もしうまくいかないときは、nginxが正しく動いていない可能性があります。先にnginxを設定してください。ssl "on" を "off" に変えてから再試行してください。 --- -* nginxコンフィギュレーションの例をnginxフォルダーにコピーします。 +* nginxの設定ファイルサンプルをnginxフォルダーにコピーします。 ``` -cp /home/pleroma/pleroma/installation/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx +sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx +sudo ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx ``` -* nginxを起動する前に、コンフィギュレーションを編集してください。例えば、サーバー名、証明書のパスなどを変更する必要があります。 +* nginxを起動する前に、設定ファイルを編集してください。例えば、サーバー名、証明書のパスなどを変更する必要があります。 * nginxを再起動します。 ``` -systemctl reload nginx.service +sudo systemctl enable --now nginx.service ``` +もし証明書を更新する必要が出てきた場合には、nginxの関連するlocationブロックのコメントアウトを外し、以下のコマンドを動かします。 + +``` +sudo certbot certonly --email -d --webroot -w /var/lib/letsencrypt/ +``` + +#### 他のWebサーバやプロキシ +これに関してはサンプルが `/opt/pleroma/installation/` にあるので、探してみてください。 + #### Systemd サービス -* サービスファイルの例をコピーします。 +* サービスファイルのサンプルをコピーします。 ``` -cp /home/pleroma/pleroma/installation/pleroma.service /usr/lib/systemd/system/pleroma.service +sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service ``` -* サービスファイルを変更します。すべてのパスが正しいことを確認してください。また、`[Service]` セクションに以下の行があることを確認してください。 +* サービスファイルを変更します。すべてのパスが正しいことを確認してください +* サービスを有効化し `pleroma.service` を開始してください ``` -Environment="MIX_ENV=prod" +sudo systemctl enable --now pleroma.service ``` -* `pleroma.service` を enable および start してください。 +#### 初期ユーザの作成 + +新たにインスタンスを作成したら、以下のコマンドにより管理者権限を持った初期ユーザを作成できます。 + ``` -systemctl enable --now pleroma.service +sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new --admin ``` -#### モデレーターを作る - -新たにユーザーを作ったら、モデレーター権限を与えたいかもしれません。以下のタスクで可能です。 -``` -mix set_moderator username [true|false] -``` - -モデレーターはすべてのポストを消すことができます。将来的には他のことも可能になるかもしれません。 - -#### メディアプロクシを有効にする - -`generate_config` でメディアプロクシを有効にしているなら、すでにメディアプロクシが動作しています。あとから設定を変更したいなら、[How to activate mediaproxy](How-to-activate-mediaproxy) を見てください。 - -#### コンフィギュレーションとカスタマイズ +#### その他の設定とカスタマイズ * [Backup your instance](backup.html) * [Configuration tips](general-tips-for-customizing-pleroma-fe.html) From a90ea8ba1562818b025f677ffeea35f7ca08ddf2 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sat, 31 Aug 2019 19:08:56 +0300 Subject: [PATCH 022/272] [#1149] Addressed code review comments (code style, jobs pruning etc.). --- CHANGELOG.md | 2 +- config/config.exs | 2 +- config/test.exs | 2 + docs/config.md | 56 ++++++++++++++++++- lib/pleroma/activity_expiration_worker.ex | 6 +- lib/pleroma/application.ex | 2 +- lib/pleroma/digest_email_worker.ex | 4 +- lib/pleroma/emails/mailer.ex | 4 +- lib/pleroma/scheduled_activity_worker.ex | 2 +- lib/pleroma/user.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- .../mrf/mediaproxy_warming_policy.ex | 2 +- lib/pleroma/web/activity_pub/publisher.ex | 2 +- .../web/activity_pub/transmogrifier.ex | 4 +- lib/pleroma/web/federator/federator.ex | 8 +-- lib/pleroma/web/federator/publisher.ex | 9 +-- lib/pleroma/web/oauth/token/clean_worker.ex | 2 +- lib/pleroma/web/push/push.ex | 6 +- lib/pleroma/web/salmon/salmon.ex | 2 +- .../workers/activity_expiration_worker.ex | 21 +++++++ lib/pleroma/workers/background_worker.ex | 19 ++----- lib/pleroma/workers/helper.ex | 13 ----- .../workers/{mailer.ex => mailer_worker.ex} | 19 +++---- .../{publisher.ex => publisher_worker.ex} | 8 ++- .../{receiver.ex => receiver_worker.ex} | 4 +- .../workers/scheduled_activity_worker.ex | 2 +- .../{subscriber.ex => subscriber_worker.ex} | 4 +- ...smogrifier.ex => transmogrifier_worker.ex} | 6 +- .../{web_pusher.ex => web_pusher_worker.ex} | 4 +- lib/pleroma/workers/worker_helper.ex | 23 ++++++++ test/user_test.exs | 2 +- .../activity_pub_controller_test.exs | 2 +- test/web/federator_test.exs | 2 +- test/web/websub/websub_test.exs | 2 +- 34 files changed, 163 insertions(+), 87 deletions(-) create mode 100644 lib/pleroma/workers/activity_expiration_worker.ex delete mode 100644 lib/pleroma/workers/helper.ex rename lib/pleroma/workers/{mailer.ex => mailer_worker.ex} (58%) rename lib/pleroma/workers/{publisher.ex => publisher_worker.ex} (76%) rename lib/pleroma/workers/{receiver.ex => receiver_worker.ex} (83%) rename lib/pleroma/workers/{subscriber.ex => subscriber_worker.ex} (88%) rename lib/pleroma/workers/{transmogrifier.ex => transmogrifier_worker.ex} (73%) rename lib/pleroma/workers/{web_pusher.ex => web_pusher_worker.ex} (82%) create mode 100644 lib/pleroma/workers/worker_helper.ex diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b73c783f..c9d6fef17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Unsubscribe followers when they unfollow a user - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) - Improve digest email template -- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) with [Oban](https://github.com/sorentwo/oban) +- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings). - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler ### Fixed diff --git a/config/config.exs b/config/config.exs index da89aa3e9..6fb4a0969 100644 --- a/config/config.exs +++ b/config/config.exs @@ -470,7 +470,7 @@ config :pleroma, Oban, repo: Pleroma.Repo, verbose: false, - prune: {:maxage, 60 * 60 * 24 * 7}, + prune: {:maxlen, 1500}, queues: [ activity_expiration: 10, federator_incoming: 50, diff --git a/config/test.exs b/config/test.exs index 0ef809ac1..df512b5d7 100644 --- a/config/test.exs +++ b/config/test.exs @@ -65,6 +65,8 @@ queues: false, prune: :disabled +config :pleroma, Pleroma.Scheduler, jobs: [] + config :pleroma, Pleroma.ScheduledActivity, daily_user_limit: 2, total_user_limit: 3, diff --git a/docs/config.md b/docs/config.md index 2e351e272..29a4d4c97 100644 --- a/docs/config.md +++ b/docs/config.md @@ -404,20 +404,29 @@ curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerando [Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration. +Configuration options described in [Oban readme](https://github.com/sorentwo/oban#usage): +* `repo` - app's Ecto repo (`Pleroma.Repo`) +* `verbose` - logs verbosity +* `prune` - non-retryable jobs [pruning settings](https://github.com/sorentwo/oban#pruning) (`:disabled` / `{:maxlen, value}` / `{:maxage, value}`) +* `queues` - job queues (see below) + Pleroma has the following queues: +* `activity_expiration` - Activity expiration * `federator_outgoing` - Outgoing federation * `federator_incoming` - Incoming federation -* `mailer` - Email sender, see [`Pleroma.Emails.Mailer`](#pleroma-emails-mailer) +* `mailer` - Email sender, see [`Pleroma.Emails.Mailer`](#pleromaemailsmailer) * `transmogrifier` - Transmogrifier * `web_push` - Web push notifications -* `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivities`](#pleromascheduledactivity) +* `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivity`](#pleromascheduledactivity) Example: ```elixir config :pleroma, Oban, repo: Pleroma.Repo, + verbose: false, + prune: {:maxlen, 1500}, queues: [ federator_incoming: 50, federator_outgoing: 50 @@ -426,12 +435,37 @@ config :pleroma, Oban, This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the number of max concurrent jobs set to `50`. +### Migrating `pleroma_job_queue` settings + +`config :pleroma_job_queue, :queues` is replaced by `config :pleroma, Oban, :queues` and uses the same format (keys are queues' names, values are max concurrent jobs numbers). + +### Note on running with PostgreSQL in silent mode + +If you are running PostgreSQL in [`silent_mode`](https://postgresqlco.nf/en/doc/param/silent_mode?version=9.1), it's advised to set [`log_destination`](https://postgresqlco.nf/en/doc/param/log_destination?version=9.1) to `syslog`, +otherwise `postmaster.log` file may grow because of "you don't own a lock of type ShareLock" warnings (see https://github.com/sorentwo/oban/issues/52). + ## :workers Includes custom worker options not interpretable directly by `Oban`. * `retries` — keyword lists where keys are `Oban` queues (see above) and values are numbers of max attempts for failed jobs. +Example: + +```elixir +config :pleroma, :workers, + retries: [ + federator_incoming: 5, + federator_outgoing: 5 + ] +``` + +### Migrating `Pleroma.Web.Federator.RetryQueue` settings + +* `max_retries` is replaced with `config :pleroma, :workers, retries: [federator_outgoing: 5]` +* `enabled: false` corresponds to `config :pleroma, :workers, retries: [federator_outgoing: 1]` +* deprecated options: `max_jobs`, `initial_timeout` + ## Pleroma.Web.Metadata * `providers`: a list of metadata providers to enable. Providers available: * Pleroma.Web.Metadata.Providers.OpenGraph @@ -491,6 +525,24 @@ config :auto_linker, ] ``` +## Pleroma.Scheduler + +Configuration for [Quantum](https://github.com/quantum-elixir/quantum-core) jobs scheduler. + +See [Quantum readme](https://github.com/quantum-elixir/quantum-core#usage) for the list of supported options. + +Example: + +```elixir +config :pleroma, Pleroma.Scheduler, + global: true, + overlap: true, + timezone: :utc, + jobs: [{"0 */6 * * * *", {Pleroma.Web.Websub, :refresh_subscriptions, []}}] +``` + +The above example defines a single job which invokes `Pleroma.Web.Websub.refresh_subscriptions()` every 6 hours ("0 */6 * * * *", [crontab format](https://en.wikipedia.org/wiki/Cron)). + ## Pleroma.ScheduledActivity * `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`) diff --git a/lib/pleroma/activity_expiration_worker.ex b/lib/pleroma/activity_expiration_worker.ex index 5c0c53232..7aba7eece 100644 --- a/lib/pleroma/activity_expiration_worker.ex +++ b/lib/pleroma/activity_expiration_worker.ex @@ -9,13 +9,13 @@ defmodule Pleroma.ActivityExpirationWorker do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI - alias Pleroma.Workers.BackgroundWorker + alias Pleroma.Workers.ActivityExpirationWorker require Logger use GenServer import Ecto.Query - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] @schedule_interval :timer.minutes(1) @@ -57,7 +57,7 @@ def handle_info(:perform, state) do "op" => "activity_expiration", "activity_expiration_id" => expiration.id } - |> BackgroundWorker.new(worker_args(:activity_expiration)) + |> ActivityExpirationWorker.new(worker_args(:activity_expiration)) |> Repo.insert() end) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 7d38ed5c4..f8f866dbd 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -43,7 +43,7 @@ def start(_type, _args) do hackney_pool_children() ++ [ Pleroma.Stats, - {Oban, Application.get_env(:pleroma, Oban)}, + {Oban, Pleroma.Config.get(Oban)}, %{ id: :web_push_init, start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index ffc48bfab..4ab2a4ef4 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -4,11 +4,11 @@ defmodule Pleroma.DigestEmailWorker do alias Pleroma.Repo - alias Pleroma.Workers.Mailer, as: MailerWorker + alias Pleroma.Workers.MailerWorker import Ecto.Query - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] def perform do config = Pleroma.Config.get([:email_notifications, :digest]) diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex index bb534f602..9cbe7313c 100644 --- a/lib/pleroma/emails/mailer.ex +++ b/lib/pleroma/emails/mailer.ex @@ -10,7 +10,7 @@ defmodule Pleroma.Emails.Mailer do """ alias Pleroma.Repo - alias Pleroma.Workers.Mailer, as: MailerWorker + alias Pleroma.Workers.MailerWorker alias Swoosh.DeliveryError @otp_app :pleroma @@ -19,7 +19,7 @@ defmodule Pleroma.Emails.Mailer do @spec enabled?() :: boolean() def enabled?, do: Pleroma.Config.get([__MODULE__, :enabled]) - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] @doc "add email to queue" def deliver_async(email, config \\ []) do diff --git a/lib/pleroma/scheduled_activity_worker.ex b/lib/pleroma/scheduled_activity_worker.ex index a01fb4fcb..8bf534f42 100644 --- a/lib/pleroma/scheduled_activity_worker.ex +++ b/lib/pleroma/scheduled_activity_worker.ex @@ -18,7 +18,7 @@ defmodule Pleroma.ScheduledActivityWorker do @schedule_interval :timer.minutes(1) - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] def start_link(_) do GenServer.start_link(__MODULE__, nil) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 18bba0fbb..abfa063fb 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -41,7 +41,7 @@ defmodule Pleroma.User do @strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/ @extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/ - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] schema "users" do field(:bio, :string) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 50279cca5..74c5eb91c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do require Logger require Pleroma.Constants - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] # For Announce activities, we filter the recipients based on following status for any actors # that match actual users. See issue #164 for more information about why this is necessary. diff --git a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex index b188164ee..178321558 100644 --- a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex @@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do recv_timeout: 10_000 ] - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] def perform(:prefetch, url) do Logger.info("Prefetching #{inspect(url)}") diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 24d101dc8..a6322e25a 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -85,7 +85,7 @@ def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = pa end def publish_one(%{actor_id: actor_id} = params) do - actor = User.get_by_id(actor_id) + actor = User.get_cached_by_id(actor_id) params |> Map.delete(:actor_id) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index b068d28a7..9437f9a16 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -15,14 +15,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator - alias Pleroma.Workers.Transmogrifier, as: TransmogrifierWorker + alias Pleroma.Workers.TransmogrifierWorker import Ecto.Query require Logger require Pleroma.Constants - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] @doc """ Modifies an incoming AP object (mastodon format) to our internal format. diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index cf7e50fee..8f43066e3 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -12,13 +12,13 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.OStatus alias Pleroma.Web.Websub - alias Pleroma.Workers.Publisher, as: PublisherWorker - alias Pleroma.Workers.Receiver, as: ReceiverWorker - alias Pleroma.Workers.Subscriber, as: SubscriberWorker + alias Pleroma.Workers.PublisherWorker + alias Pleroma.Workers.ReceiverWorker + alias Pleroma.Workers.SubscriberWorker require Logger - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] def init do # To do: consider removing this call in favor of scheduled execution (`quantum`-based) diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 05d2be615..42be109ab 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.Federator.Publisher do alias Pleroma.Activity alias Pleroma.Config alias Pleroma.User - alias Pleroma.Workers.Publisher, as: PublisherWorker + alias Pleroma.Workers.PublisherWorker require Logger @@ -31,12 +31,7 @@ defmodule Pleroma.Web.Federator.Publisher do """ @spec enqueue_one(module(), Map.t()) :: :ok def enqueue_one(module, %{} = params) do - worker_args = - if max_attempts = Pleroma.Config.get([:workers, :retries, :federator_outgoing]) do - [max_attempts: max_attempts] - else - [] - end + worker_args = Pleroma.Workers.WorkerHelper.worker_args(:federator_outgoing) %{"op" => "publish_one", "module" => to_string(module), "params" => params} |> PublisherWorker.new(worker_args) diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex index 943e73289..b150a68a7 100644 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do alias Pleroma.Web.OAuth.Token alias Pleroma.Workers.BackgroundWorker - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] def start_link(_), do: GenServer.start_link(__MODULE__, %{}) diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex index b4f0e5127..4973b529c 100644 --- a/lib/pleroma/web/push/push.ex +++ b/lib/pleroma/web/push/push.ex @@ -4,11 +4,11 @@ defmodule Pleroma.Web.Push do alias Pleroma.Repo - alias Pleroma.Workers.WebPusher + alias Pleroma.Workers.WebPusherWorker require Logger - defdelegate worker_args(queue), to: Pleroma.Workers.Helper + import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] def init do unless enabled() do @@ -36,7 +36,7 @@ def enabled do def send(notification) do %{"op" => "web_push", "notification_id" => notification.id} - |> WebPusher.new(worker_args(:web_push)) + |> WebPusherWorker.new(worker_args(:web_push)) |> Repo.insert() end end diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index bbaa293fd..8ba7380c0 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -171,7 +171,7 @@ def publish_one(%{recipient: url, feed: feed} = params) when is_binary(url) do end def publish_one(%{recipient_id: recipient_id} = params) do - recipient = User.get_by_id(recipient_id) + recipient = User.get_cached_by_id(recipient_id) params |> Map.delete(:recipient_id) diff --git a/lib/pleroma/workers/activity_expiration_worker.ex b/lib/pleroma/workers/activity_expiration_worker.ex new file mode 100644 index 000000000..0b491eabb --- /dev/null +++ b/lib/pleroma/workers/activity_expiration_worker.ex @@ -0,0 +1,21 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.ActivityExpirationWorker do + # Note: `max_attempts` is intended to be overridden in `new/2` call + use Oban.Worker, + queue: "activity_expiration", + max_attempts: 1 + + @impl Oban.Worker + def perform( + %{ + "op" => "activity_expiration", + "activity_expiration_id" => activity_expiration_id + }, + _job + ) do + Pleroma.ActivityExpirationWorker.perform(:execute, activity_expiration_id) + end +end diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index fbce7d789..7b5575a5f 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -8,24 +8,24 @@ defmodule Pleroma.Workers.BackgroundWorker do alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy alias Pleroma.Web.OAuth.Token.CleanWorker - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "background", max_attempts: 1 @impl Oban.Worker def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}, _job) do - user = User.get_by_id(user_id) + user = User.get_cached_by_id(user_id) User.perform(:fetch_initial_posts, user) end def perform(%{"op" => "deactivate_user", "user_id" => user_id, "status" => status}, _job) do - user = User.get_by_id(user_id) + user = User.get_cached_by_id(user_id) User.perform(:deactivate_async, user, status) end def perform(%{"op" => "delete_user", "user_id" => user_id}, _job) do - user = User.get_by_id(user_id) + user = User.get_cached_by_id(user_id) User.perform(:delete, user) end @@ -37,7 +37,7 @@ def perform( }, _job ) do - blocker = User.get_by_id(blocker_id) + blocker = User.get_cached_by_id(blocker_id) User.perform(:blocks_import, blocker, blocked_identifiers) end @@ -49,7 +49,7 @@ def perform( }, _job ) do - follower = User.get_by_id(follower_id) + follower = User.get_cached_by_id(follower_id) User.perform(:follow_import, follower, followed_identifiers) end @@ -69,11 +69,4 @@ def perform(%{"op" => "fetch_data_for_activity", "activity_id" => activity_id}, activity = Activity.get_by_id(activity_id) Pleroma.Web.RichMedia.Helpers.perform(:fetch, activity) end - - def perform( - %{"op" => "activity_expiration", "activity_expiration_id" => activity_expiration_id}, - _job - ) do - Pleroma.ActivityExpirationWorker.perform(:execute, activity_expiration_id) - end end diff --git a/lib/pleroma/workers/helper.ex b/lib/pleroma/workers/helper.ex deleted file mode 100644 index 3286ce0e8..000000000 --- a/lib/pleroma/workers/helper.ex +++ /dev/null @@ -1,13 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Workers.Helper do - def worker_args(queue) do - if max_attempts = Pleroma.Config.get([:workers, :retries, queue]) do - [max_attempts: max_attempts] - else - [] - end - end -end diff --git a/lib/pleroma/workers/mailer.ex b/lib/pleroma/workers/mailer_worker.ex similarity index 58% rename from lib/pleroma/workers/mailer.ex rename to lib/pleroma/workers/mailer_worker.ex index 1cce2ea03..4f73d61bc 100644 --- a/lib/pleroma/workers/mailer.ex +++ b/lib/pleroma/workers/mailer_worker.ex @@ -2,26 +2,25 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Workers.Mailer do +defmodule Pleroma.Workers.MailerWorker do alias Pleroma.User - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "mailer", max_attempts: 1 @impl Oban.Worker def perform(%{"op" => "email", "encoded_email" => encoded_email, "config" => config}, _job) do - email = - encoded_email - |> Base.decode64!() - |> :erlang.binary_to_term() - - Pleroma.Emails.Mailer.deliver(email, config) + encoded_email + |> Base.decode64!() + |> :erlang.binary_to_term() + |> Pleroma.Emails.Mailer.deliver(config) end def perform(%{"op" => "digest_email", "user_id" => user_id}, _job) do - user = User.get_by_id(user_id) - Pleroma.DigestEmailWorker.perform(user) + user_id + |> User.get_cached_by_id() + |> Pleroma.DigestEmailWorker.perform() end end diff --git a/lib/pleroma/workers/publisher.ex b/lib/pleroma/workers/publisher_worker.ex similarity index 76% rename from lib/pleroma/workers/publisher.ex rename to lib/pleroma/workers/publisher_worker.ex index 00fae99c7..5671d2a29 100644 --- a/lib/pleroma/workers/publisher.ex +++ b/lib/pleroma/workers/publisher_worker.ex @@ -2,15 +2,19 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Workers.Publisher do +defmodule Pleroma.Workers.PublisherWorker do alias Pleroma.Activity alias Pleroma.Web.Federator - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "federator_outgoing", max_attempts: 1 + def backoff(attempt) when is_integer(attempt) do + Pleroma.Workers.WorkerHelper.sidekiq_backoff(attempt, 5) + end + @impl Oban.Worker def perform(%{"op" => "publish", "activity_id" => activity_id}, _job) do activity = Activity.get_by_id(activity_id) diff --git a/lib/pleroma/workers/receiver.ex b/lib/pleroma/workers/receiver_worker.ex similarity index 83% rename from lib/pleroma/workers/receiver.ex rename to lib/pleroma/workers/receiver_worker.ex index 4ee270d74..cdce630f2 100644 --- a/lib/pleroma/workers/receiver.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -2,10 +2,10 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Workers.Receiver do +defmodule Pleroma.Workers.ReceiverWorker do alias Pleroma.Web.Federator - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "federator_incoming", max_attempts: 1 diff --git a/lib/pleroma/workers/scheduled_activity_worker.ex b/lib/pleroma/workers/scheduled_activity_worker.ex index d9724c78a..4094411ae 100644 --- a/lib/pleroma/workers/scheduled_activity_worker.ex +++ b/lib/pleroma/workers/scheduled_activity_worker.ex @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.ScheduledActivityWorker do - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "scheduled_activities", max_attempts: 1 diff --git a/lib/pleroma/workers/subscriber.ex b/lib/pleroma/workers/subscriber_worker.ex similarity index 88% rename from lib/pleroma/workers/subscriber.ex rename to lib/pleroma/workers/subscriber_worker.ex index e960b35bf..22d1dc956 100644 --- a/lib/pleroma/workers/subscriber.ex +++ b/lib/pleroma/workers/subscriber_worker.ex @@ -2,12 +2,12 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Workers.Subscriber do +defmodule Pleroma.Workers.SubscriberWorker do alias Pleroma.Repo alias Pleroma.Web.Federator alias Pleroma.Web.Websub - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "federator_outgoing", max_attempts: 1 diff --git a/lib/pleroma/workers/transmogrifier.ex b/lib/pleroma/workers/transmogrifier_worker.ex similarity index 73% rename from lib/pleroma/workers/transmogrifier.ex rename to lib/pleroma/workers/transmogrifier_worker.ex index e13202c06..6f5c1a2f2 100644 --- a/lib/pleroma/workers/transmogrifier.ex +++ b/lib/pleroma/workers/transmogrifier_worker.ex @@ -2,17 +2,17 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Workers.Transmogrifier do +defmodule Pleroma.Workers.TransmogrifierWorker do alias Pleroma.User - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "transmogrifier", max_attempts: 1 @impl Oban.Worker def perform(%{"op" => "user_upgrade", "user_id" => user_id}, _job) do - user = User.get_by_id(user_id) + user = User.get_cached_by_id(user_id) Pleroma.Web.ActivityPub.Transmogrifier.perform(:user_upgrade, user) end end diff --git a/lib/pleroma/workers/web_pusher.ex b/lib/pleroma/workers/web_pusher_worker.ex similarity index 82% rename from lib/pleroma/workers/web_pusher.ex rename to lib/pleroma/workers/web_pusher_worker.ex index 7b78bb3ea..2b1d3b99a 100644 --- a/lib/pleroma/workers/web_pusher.ex +++ b/lib/pleroma/workers/web_pusher_worker.ex @@ -2,11 +2,11 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Workers.WebPusher do +defmodule Pleroma.Workers.WebPusherWorker do alias Pleroma.Notification alias Pleroma.Repo - # Note: `max_attempts` is intended to be overridden in `new/1` call + # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "web_push", max_attempts: 1 diff --git a/lib/pleroma/workers/worker_helper.ex b/lib/pleroma/workers/worker_helper.ex new file mode 100644 index 000000000..f9ed2e64d --- /dev/null +++ b/lib/pleroma/workers/worker_helper.ex @@ -0,0 +1,23 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.WorkerHelper do + alias Pleroma.Config + + def worker_args(queue) do + case Config.get([:workers, :retries, queue]) do + nil -> [] + max_attempts -> [max_attempts: max_attempts] + end + end + + def sidekiq_backoff(attempt, pow \\ 4, base_backoff \\ 15) do + backoff = + :math.pow(attempt, pow) + + base_backoff + + :rand.uniform(2 * base_backoff) * attempt + + trunc(backoff) + end +end diff --git a/test/user_test.exs b/test/user_test.exs index 86232de99..0acd0db4e 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1123,7 +1123,7 @@ test "it deletes a user, all follow relationships and all activities", %{user: u "id" => "pleroma:fakeid" } }, - all_enqueued(worker: Pleroma.Workers.Publisher) + all_enqueued(worker: Pleroma.Workers.PublisherWorker) ) end end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index a1b567a46..f1c1bb503 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI - alias Pleroma.Workers.Receiver, as: ReceiverWorker + alias Pleroma.Workers.ReceiverWorker setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 5724672fd..4096d4690 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -7,7 +7,7 @@ defmodule Pleroma.Web.FederatorTest do alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.CommonAPI alias Pleroma.Web.Federator - alias Pleroma.Workers.Publisher, as: PublisherWorker + alias Pleroma.Workers.PublisherWorker use Pleroma.DataCase use Oban.Testing, repo: Pleroma.Repo diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs index 414610879..929acf5a2 100644 --- a/test/web/websub/websub_test.exs +++ b/test/web/websub/websub_test.exs @@ -11,7 +11,7 @@ defmodule Pleroma.Web.WebsubTest do alias Pleroma.Web.Websub alias Pleroma.Web.Websub.WebsubClientSubscription alias Pleroma.Web.Websub.WebsubServerSubscription - alias Pleroma.Workers.Subscriber, as: SubscriberWorker + alias Pleroma.Workers.SubscriberWorker import Pleroma.Factory import Tesla.Mock From dd017c65a4b86501c435f5cb01804300e6b7c6dd Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sat, 31 Aug 2019 21:58:42 +0300 Subject: [PATCH 023/272] [#1149] Refactored Oban workers API (introduced `enqueue/3`). --- lib/pleroma/activity_expiration_worker.ex | 13 +++------ lib/pleroma/digest_email_worker.ex | 10 ++----- lib/pleroma/emails/mailer.ex | 7 +---- lib/pleroma/scheduled_activity_worker.ex | 10 +++---- lib/pleroma/user.ex | 28 +++++-------------- lib/pleroma/web/activity_pub/activity_pub.ex | 6 +--- .../mrf/mediaproxy_warming_policy.ex | 11 ++------ .../web/activity_pub/transmogrifier.ex | 6 +--- lib/pleroma/web/federator/federator.ex | 26 ++++------------- lib/pleroma/web/federator/publisher.ex | 9 +++--- lib/pleroma/web/oauth/token/clean_worker.ex | 7 +---- lib/pleroma/web/push/push.ex | 7 +---- .../workers/activity_expiration_worker.ex | 2 ++ lib/pleroma/workers/background_worker.ex | 2 ++ lib/pleroma/workers/digest_emails_worker.ex | 21 ++++++++++++++ lib/pleroma/workers/mailer_worker.ex | 10 ++----- lib/pleroma/workers/publisher_worker.ex | 2 ++ lib/pleroma/workers/receiver_worker.ex | 2 ++ .../workers/scheduled_activity_worker.ex | 2 ++ lib/pleroma/workers/subscriber_worker.ex | 2 ++ lib/pleroma/workers/transmogrifier_worker.ex | 2 ++ lib/pleroma/workers/web_pusher_worker.ex | 2 ++ lib/pleroma/workers/worker_helper.ex | 18 ++++++++++++ 23 files changed, 92 insertions(+), 113 deletions(-) create mode 100644 lib/pleroma/workers/digest_emails_worker.ex diff --git a/lib/pleroma/activity_expiration_worker.ex b/lib/pleroma/activity_expiration_worker.ex index 7aba7eece..c0820c202 100644 --- a/lib/pleroma/activity_expiration_worker.ex +++ b/lib/pleroma/activity_expiration_worker.ex @@ -9,14 +9,11 @@ defmodule Pleroma.ActivityExpirationWorker do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI - alias Pleroma.Workers.ActivityExpirationWorker require Logger use GenServer import Ecto.Query - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - @schedule_interval :timer.minutes(1) def start_link(_) do @@ -53,12 +50,10 @@ def perform(:execute, expiration_id) do def handle_info(:perform, state) do ActivityExpiration.due_expirations(@schedule_interval) |> Enum.each(fn expiration -> - %{ - "op" => "activity_expiration", - "activity_expiration_id" => expiration.id - } - |> ActivityExpirationWorker.new(worker_args(:activity_expiration)) - |> Repo.insert() + Pleroma.Workers.ActivityExpirationWorker.enqueue( + "activity_expiration", + %{"activity_expiration_id" => expiration.id} + ) end) schedule_next() diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index 4ab2a4ef4..5be7cf26b 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -4,12 +4,10 @@ defmodule Pleroma.DigestEmailWorker do alias Pleroma.Repo - alias Pleroma.Workers.MailerWorker + alias Pleroma.Workers.DigestEmailsWorker import Ecto.Query - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - def perform do config = Pleroma.Config.get([:email_notifications, :digest]) negative_interval = -Map.fetch!(config, :interval) @@ -23,11 +21,9 @@ def perform do where: u.last_digest_emailed_at < datetime_add(^now, ^negative_interval, "day"), select: u ) - |> Pleroma.Repo.all() + |> Repo.all() |> Enum.each(fn user -> - %{"op" => "digest_email", "user_id" => user.id} - |> MailerWorker.new([queue: "digest_emails"] ++ worker_args(:digest_emails)) - |> Repo.insert() + DigestEmailsWorker.enqueue("digest_email", %{"user_id" => user.id}) end) end diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex index 9cbe7313c..eb96f2e8b 100644 --- a/lib/pleroma/emails/mailer.ex +++ b/lib/pleroma/emails/mailer.ex @@ -9,7 +9,6 @@ defmodule Pleroma.Emails.Mailer do The module contains functions to delivery email using Swoosh.Mailer. """ - alias Pleroma.Repo alias Pleroma.Workers.MailerWorker alias Swoosh.DeliveryError @@ -19,8 +18,6 @@ defmodule Pleroma.Emails.Mailer do @spec enabled?() :: boolean() def enabled?, do: Pleroma.Config.get([__MODULE__, :enabled]) - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - @doc "add email to queue" def deliver_async(email, config \\ []) do encoded_email = @@ -28,9 +25,7 @@ def deliver_async(email, config \\ []) do |> :erlang.term_to_binary() |> Base.encode64() - %{"op" => "email", "encoded_email" => encoded_email, "config" => config} - |> MailerWorker.new(worker_args(:mailer)) - |> Repo.insert() + MailerWorker.enqueue("email", %{"encoded_email" => encoded_email, "config" => config}) end @doc "callback to perform send email from queue" diff --git a/lib/pleroma/scheduled_activity_worker.ex b/lib/pleroma/scheduled_activity_worker.ex index 8bf534f42..c41a542de 100644 --- a/lib/pleroma/scheduled_activity_worker.ex +++ b/lib/pleroma/scheduled_activity_worker.ex @@ -8,7 +8,6 @@ defmodule Pleroma.ScheduledActivityWorker do """ alias Pleroma.Config - alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -18,8 +17,6 @@ defmodule Pleroma.ScheduledActivityWorker do @schedule_interval :timer.minutes(1) - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - def start_link(_) do GenServer.start_link(__MODULE__, nil) end @@ -49,9 +46,10 @@ def perform(:execute, scheduled_activity_id) do def handle_info(:perform, state) do ScheduledActivity.due_activities(@schedule_interval) |> Enum.each(fn scheduled_activity -> - %{"op" => "execute", "activity_id" => scheduled_activity.id} - |> Pleroma.Workers.ScheduledActivityWorker.new(worker_args(:scheduled_activities)) - |> Repo.insert() + Pleroma.Workers.ScheduledActivityWorker.enqueue( + "execute", + %{"activity_id" => scheduled_activity.id} + ) end) schedule_next() diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index abfa063fb..2fe7e1748 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -41,8 +41,6 @@ defmodule Pleroma.User do @strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/ @extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/ - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - schema "users" do field(:bio, :string) field(:email, :string) @@ -623,9 +621,7 @@ def get_or_fetch_by_nickname(nickname) do @doc "Fetch some posts when the user has just been federated with" def fetch_initial_posts(user) do - %{"op" => "fetch_initial_posts", "user_id" => user.id} - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + BackgroundWorker.enqueue("fetch_initial_posts", %{"user_id" => user.id}) end @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() @@ -1056,9 +1052,7 @@ def unblock_domain(user, domain) do end def deactivate_async(user, status \\ true) do - %{"op" => "deactivate_user", "user_id" => user.id, "status" => status} - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + BackgroundWorker.enqueue("deactivate_user", %{"user_id" => user.id, "status" => status}) end def deactivate(%User{} = user, status \\ true) do @@ -1087,9 +1081,7 @@ def update_notification_settings(%User{} = user, settings \\ %{}) do end def delete(%User{} = user) do - %{"op" => "delete_user", "user_id" => user.id} - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id}) end @spec perform(atom(), User.t()) :: {:ok, User.t()} @@ -1198,24 +1190,18 @@ def external_users(opts \\ []) do end def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do - %{ - "op" => "blocks_import", + BackgroundWorker.enqueue("blocks_import", %{ "blocker_id" => blocker.id, "blocked_identifiers" => blocked_identifiers - } - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + }) end def follow_import(%User{} = follower, followed_identifiers) when is_list(followed_identifiers) do - %{ - "op" => "follow_import", + BackgroundWorker.enqueue("follow_import", %{ "follower_id" => follower.id, "followed_identifiers" => followed_identifiers - } - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + }) end def delete_user_activities(%User{ap_id: ap_id} = user) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 74c5eb91c..90b409606 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -26,8 +26,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do require Logger require Pleroma.Constants - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - # For Announce activities, we filter the recipients based on following status for any actors # that match actual users. See issue #164 for more information about why this is necessary. defp get_recipients(%{"type" => "Announce"} = data) do @@ -148,9 +146,7 @@ def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when activity end - %{"op" => "fetch_data_for_activity", "activity_id" => activity.id} - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + BackgroundWorker.enqueue("fetch_data_for_activity", %{"activity_id" => activity.id}) Notification.create_notifications(activity) diff --git a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex index 178321558..26b8539fe 100644 --- a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex @@ -7,7 +7,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do @behaviour Pleroma.Web.ActivityPub.MRF alias Pleroma.HTTP - alias Pleroma.Repo alias Pleroma.Web.MediaProxy alias Pleroma.Workers.BackgroundWorker @@ -18,8 +17,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do recv_timeout: 10_000 ] - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - def perform(:prefetch, url) do Logger.info("Prefetching #{inspect(url)}") @@ -34,9 +31,7 @@ def perform(:preload, %{"object" => %{"attachment" => attachments}} = _message) url |> Enum.each(fn %{"href" => href} -> - %{"op" => "media_proxy_prefetch", "url" => href} - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + BackgroundWorker.enqueue("media_proxy_prefetch", %{"url" => href}) x -> Logger.debug("Unhandled attachment URL object #{inspect(x)}") @@ -52,9 +47,7 @@ def filter( %{"type" => "Create", "object" => %{"attachment" => attachments} = _object} = message ) when is_list(attachments) and length(attachments) > 0 do - %{"op" => "media_proxy_preload", "message" => message} - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + BackgroundWorker.enqueue("media_proxy_preload", %{"message" => message}) {:ok, message} end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 9437f9a16..f27455e8b 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -22,8 +22,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do require Logger require Pleroma.Constants - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - @doc """ Modifies an incoming AP object (mastodon format) to our internal format. """ @@ -1054,9 +1052,7 @@ def upgrade_user_from_ap_id(ap_id) do already_ap <- User.ap_enabled?(user), {:ok, user} <- user |> User.upgrade_changeset(data) |> User.update_and_set_cache() do unless already_ap do - %{"op" => "user_upgrade", "user_id" => user.id} - |> TransmogrifierWorker.new(worker_args(:transmogrifier)) - |> Repo.insert() + TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id}) end {:ok, user} diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 8f43066e3..1a2da014a 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -18,8 +18,6 @@ defmodule Pleroma.Web.Federator do require Logger - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - def init do # To do: consider removing this call in favor of scheduled execution (`quantum`-based) refresh_subscriptions(schedule_in: 60) @@ -40,15 +38,11 @@ def allowed_incoming_reply_depth?(depth) do # Client API def incoming_doc(doc) do - %{"op" => "incoming_doc", "body" => doc} - |> ReceiverWorker.new(worker_args(:federator_incoming)) - |> Pleroma.Repo.insert() + ReceiverWorker.enqueue("incoming_doc", %{"body" => doc}) end def incoming_ap_doc(params) do - %{"op" => "incoming_ap_doc", "params" => params} - |> ReceiverWorker.new(worker_args(:federator_incoming)) - |> Pleroma.Repo.insert() + ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params}) end def publish(%{id: "pleroma:fakeid"} = activity) do @@ -56,27 +50,19 @@ def publish(%{id: "pleroma:fakeid"} = activity) do end def publish(activity) do - %{"op" => "publish", "activity_id" => activity.id} - |> PublisherWorker.new(worker_args(:federator_outgoing)) - |> Pleroma.Repo.insert() + PublisherWorker.enqueue("publish", %{"activity_id" => activity.id}) end def verify_websub(websub) do - %{"op" => "verify_websub", "websub_id" => websub.id} - |> SubscriberWorker.new(worker_args(:federator_outgoing)) - |> Pleroma.Repo.insert() + SubscriberWorker.enqueue("verify_websub", %{"websub_id" => websub.id}) end def request_subscription(websub) do - %{"op" => "request_subscription", "websub_id" => websub.id} - |> SubscriberWorker.new(worker_args(:federator_outgoing)) - |> Pleroma.Repo.insert() + SubscriberWorker.enqueue("request_subscription", %{"websub_id" => websub.id}) end def refresh_subscriptions(worker_args \\ []) do - %{"op" => "refresh_subscriptions"} - |> SubscriberWorker.new(worker_args ++ [max_attempts: 1] ++ worker_args(:federator_outgoing)) - |> Pleroma.Repo.insert() + SubscriberWorker.enqueue("refresh_subscriptions", %{}, worker_args ++ [max_attempts: 1]) end # Job Worker Callbacks diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 42be109ab..937064638 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -31,11 +31,10 @@ defmodule Pleroma.Web.Federator.Publisher do """ @spec enqueue_one(module(), Map.t()) :: :ok def enqueue_one(module, %{} = params) do - worker_args = Pleroma.Workers.WorkerHelper.worker_args(:federator_outgoing) - - %{"op" => "publish_one", "module" => to_string(module), "params" => params} - |> PublisherWorker.new(worker_args) - |> Pleroma.Repo.insert() + PublisherWorker.enqueue( + "publish_one", + %{"module" => to_string(module), "params" => params} + ) end @doc """ diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex index b150a68a7..eb94bf86f 100644 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -16,12 +16,9 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do @one_day ) - alias Pleroma.Repo alias Pleroma.Web.OAuth.Token alias Pleroma.Workers.BackgroundWorker - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - def start_link(_), do: GenServer.start_link(__MODULE__, %{}) def init(_) do @@ -31,9 +28,7 @@ def init(_) do @doc false def handle_info(:perform, state) do - %{"op" => "clean_expired_tokens"} - |> BackgroundWorker.new(worker_args(:background)) - |> Repo.insert() + BackgroundWorker.enqueue("clean_expired_tokens", %{}) Process.send_after(self(), :perform, @interval) {:noreply, state} diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex index 4973b529c..7ef1532ac 100644 --- a/lib/pleroma/web/push/push.ex +++ b/lib/pleroma/web/push/push.ex @@ -3,13 +3,10 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Push do - alias Pleroma.Repo alias Pleroma.Workers.WebPusherWorker require Logger - import Pleroma.Workers.WorkerHelper, only: [worker_args: 1] - def init do unless enabled() do Logger.warn(""" @@ -35,8 +32,6 @@ def enabled do end def send(notification) do - %{"op" => "web_push", "notification_id" => notification.id} - |> WebPusherWorker.new(worker_args(:web_push)) - |> Repo.insert() + WebPusherWorker.enqueue("web_push", %{"notification_id" => notification.id}) end end diff --git a/lib/pleroma/workers/activity_expiration_worker.ex b/lib/pleroma/workers/activity_expiration_worker.ex index 0b491eabb..60dd3feba 100644 --- a/lib/pleroma/workers/activity_expiration_worker.ex +++ b/lib/pleroma/workers/activity_expiration_worker.ex @@ -8,6 +8,8 @@ defmodule Pleroma.Workers.ActivityExpirationWorker do queue: "activity_expiration", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "activity_expiration" + @impl Oban.Worker def perform( %{ diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 7b5575a5f..b9aef3a92 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -13,6 +13,8 @@ defmodule Pleroma.Workers.BackgroundWorker do queue: "background", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "background" + @impl Oban.Worker def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}, _job) do user = User.get_cached_by_id(user_id) diff --git a/lib/pleroma/workers/digest_emails_worker.ex b/lib/pleroma/workers/digest_emails_worker.ex new file mode 100644 index 000000000..ca073ce67 --- /dev/null +++ b/lib/pleroma/workers/digest_emails_worker.ex @@ -0,0 +1,21 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.DigestEmailsWorker do + alias Pleroma.User + + # Note: `max_attempts` is intended to be overridden in `new/2` call + use Oban.Worker, + queue: "digest_emails", + max_attempts: 1 + + use Pleroma.Workers.WorkerHelper, queue: "digest_emails" + + @impl Oban.Worker + def perform(%{"op" => "digest_email", "user_id" => user_id}, _job) do + user_id + |> User.get_cached_by_id() + |> Pleroma.DigestEmailWorker.perform() + end +end diff --git a/lib/pleroma/workers/mailer_worker.ex b/lib/pleroma/workers/mailer_worker.ex index 4f73d61bc..a4bd54a6c 100644 --- a/lib/pleroma/workers/mailer_worker.ex +++ b/lib/pleroma/workers/mailer_worker.ex @@ -3,13 +3,13 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.MailerWorker do - alias Pleroma.User - # Note: `max_attempts` is intended to be overridden in `new/2` call use Oban.Worker, queue: "mailer", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "mailer" + @impl Oban.Worker def perform(%{"op" => "email", "encoded_email" => encoded_email, "config" => config}, _job) do encoded_email @@ -17,10 +17,4 @@ def perform(%{"op" => "email", "encoded_email" => encoded_email, "config" => con |> :erlang.binary_to_term() |> Pleroma.Emails.Mailer.deliver(config) end - - def perform(%{"op" => "digest_email", "user_id" => user_id}, _job) do - user_id - |> User.get_cached_by_id() - |> Pleroma.DigestEmailWorker.perform() - end end diff --git a/lib/pleroma/workers/publisher_worker.ex b/lib/pleroma/workers/publisher_worker.ex index 5671d2a29..a3ac22635 100644 --- a/lib/pleroma/workers/publisher_worker.ex +++ b/lib/pleroma/workers/publisher_worker.ex @@ -11,6 +11,8 @@ defmodule Pleroma.Workers.PublisherWorker do queue: "federator_outgoing", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "federator_outgoing" + def backoff(attempt) when is_integer(attempt) do Pleroma.Workers.WorkerHelper.sidekiq_backoff(attempt, 5) end diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex index cdce630f2..3cc415ce4 100644 --- a/lib/pleroma/workers/receiver_worker.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -10,6 +10,8 @@ defmodule Pleroma.Workers.ReceiverWorker do queue: "federator_incoming", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "federator_incoming" + @impl Oban.Worker def perform(%{"op" => "incoming_doc", "body" => doc}, _job) do Federator.perform(:incoming_doc, doc) diff --git a/lib/pleroma/workers/scheduled_activity_worker.ex b/lib/pleroma/workers/scheduled_activity_worker.ex index 4094411ae..936bb64d3 100644 --- a/lib/pleroma/workers/scheduled_activity_worker.ex +++ b/lib/pleroma/workers/scheduled_activity_worker.ex @@ -8,6 +8,8 @@ defmodule Pleroma.Workers.ScheduledActivityWorker do queue: "scheduled_activities", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "scheduled_activities" + @impl Oban.Worker def perform(%{"op" => "execute", "activity_id" => activity_id}, _job) do Pleroma.ScheduledActivityWorker.perform(:execute, activity_id) diff --git a/lib/pleroma/workers/subscriber_worker.ex b/lib/pleroma/workers/subscriber_worker.ex index 22d1dc956..4fb994554 100644 --- a/lib/pleroma/workers/subscriber_worker.ex +++ b/lib/pleroma/workers/subscriber_worker.ex @@ -12,6 +12,8 @@ defmodule Pleroma.Workers.SubscriberWorker do queue: "federator_outgoing", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "federator_outgoing" + @impl Oban.Worker def perform(%{"op" => "refresh_subscriptions"}, _job) do Federator.perform(:refresh_subscriptions) diff --git a/lib/pleroma/workers/transmogrifier_worker.ex b/lib/pleroma/workers/transmogrifier_worker.ex index 6f5c1a2f2..6fecc2bf9 100644 --- a/lib/pleroma/workers/transmogrifier_worker.ex +++ b/lib/pleroma/workers/transmogrifier_worker.ex @@ -10,6 +10,8 @@ defmodule Pleroma.Workers.TransmogrifierWorker do queue: "transmogrifier", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "transmogrifier" + @impl Oban.Worker def perform(%{"op" => "user_upgrade", "user_id" => user_id}, _job) do user = User.get_cached_by_id(user_id) diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex index 2b1d3b99a..4c2591a5c 100644 --- a/lib/pleroma/workers/web_pusher_worker.ex +++ b/lib/pleroma/workers/web_pusher_worker.ex @@ -11,6 +11,8 @@ defmodule Pleroma.Workers.WebPusherWorker do queue: "web_push", max_attempts: 1 + use Pleroma.Workers.WorkerHelper, queue: "web_push" + @impl Oban.Worker def perform(%{"op" => "web_push", "notification_id" => notification_id}, _job) do notification = Repo.get(Notification, notification_id) diff --git a/lib/pleroma/workers/worker_helper.ex b/lib/pleroma/workers/worker_helper.ex index f9ed2e64d..b12f198d4 100644 --- a/lib/pleroma/workers/worker_helper.ex +++ b/lib/pleroma/workers/worker_helper.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Workers.WorkerHelper do alias Pleroma.Config + alias Pleroma.Workers.WorkerHelper def worker_args(queue) do case Config.get([:workers, :retries, queue]) do @@ -20,4 +21,21 @@ def sidekiq_backoff(attempt, pow \\ 4, base_backoff \\ 15) do trunc(backoff) end + + defmacro __using__(opts) do + caller_module = __CALLER__.module + queue = Keyword.fetch!(opts, :queue) + + quote do + def enqueue(op, params, worker_args \\ []) do + params = Map.merge(%{"op" => op}, params) + queue_atom = String.to_atom(unquote(queue)) + worker_args = worker_args ++ WorkerHelper.worker_args(queue_atom) + + unquote(caller_module) + |> apply(:new, [params, worker_args]) + |> Pleroma.Repo.insert() + end + end + end end From 9c96b17e16a4911d3e20149e1b54b12baaf71617 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 1 Sep 2019 21:23:30 +0300 Subject: [PATCH 024/272] Add pagination to logs --- lib/pleroma/moderation_log.ex | 29 +++++++++++++------ .../admin_api/views/moderation_log_view.ex | 5 +++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 89a5e13c3..352cad433 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -15,12 +15,18 @@ defmodule Pleroma.ModerationLog do end def get_all(params) do - params - |> get_all_query() - |> maybe_filter_by_date(params) - |> maybe_filter_by_user(params) - |> maybe_filter_by_search(params) - |> Repo.all() + base_query = + get_all_query() + |> maybe_filter_by_date(params) + |> maybe_filter_by_user(params) + |> maybe_filter_by_search(params) + + query_with_pagination = base_query |> paginate_query(params) + + %{ + items: Repo.all(query_with_pagination), + count: Repo.aggregate(base_query, :count, :id) + } end defp maybe_filter_by_date(query, %{start_date: nil, end_date: nil}), do: query @@ -61,14 +67,19 @@ defp maybe_filter_by_search(query, %{search: search}) do ) end - defp get_all_query(%{page: page, page_size: page_size}) do - from(q in __MODULE__, - order_by: [desc: q.inserted_at], + defp paginate_query(query, %{page: page, page_size: page_size}) do + from(q in query, limit: ^page_size, offset: ^((page - 1) * page_size) ) end + defp get_all_query do + from(q in __MODULE__, + order_by: [desc: q.inserted_at] + ) + end + defp parse_datetime(datetime) do {:ok, parsed_datetime, _} = DateTime.from_iso8601(datetime) diff --git a/lib/pleroma/web/admin_api/views/moderation_log_view.ex b/lib/pleroma/web/admin_api/views/moderation_log_view.ex index b3fc7cfe5..e7752d1f3 100644 --- a/lib/pleroma/web/admin_api/views/moderation_log_view.ex +++ b/lib/pleroma/web/admin_api/views/moderation_log_view.ex @@ -8,7 +8,10 @@ defmodule Pleroma.Web.AdminAPI.ModerationLogView do alias Pleroma.ModerationLog def render("index.json", %{log: log}) do - render_many(log, __MODULE__, "show.json", as: :log_entry) + %{ + items: render_many(log.items, __MODULE__, "show.json", as: :log_entry), + total: log.count + } end def render("show.json", %{log_entry: log_entry}) do From c5ffbfb8d547199f2345e28f085dd12e8b443f21 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 1 Sep 2019 21:25:55 +0300 Subject: [PATCH 025/272] Changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fdcb014a..0d44944eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mix Tasks: `mix pleroma.database fix_likes_collections` - Federation: Remove `likes` from objects. - Admin API: Added moderation log +- Admin API: Added moderation log filters (user/start date/end date/search/pagination) ### Changed - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text From 6c2fd1b78bbbb4486a5dddeffa053199ba8cc015 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 1 Sep 2019 21:38:15 +0300 Subject: [PATCH 026/272] Fix tests --- .../admin_api/admin_api_controller_test.exs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index eaf847b25..b87fffc34 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -2286,9 +2286,9 @@ test "returns the log", %{conn: conn, admin: admin} do conn = get(conn, "/api/pleroma/admin/moderation_log") response = json_response(conn, 200) - [first_entry, second_entry] = response + [first_entry, second_entry] = response["items"] - assert response |> length() == 2 + assert response["total"] == 2 assert first_entry["data"]["action"] == "relay_unfollow" assert first_entry["message"] == @@ -2330,9 +2330,10 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1") response1 = json_response(conn1, 200) - [first_entry] = response1 + [first_entry] = response1["items"] - assert response1 |> length() == 1 + assert response1["total"] == 2 + assert response1["items"] |> length() == 1 assert first_entry["data"]["action"] == "relay_unfollow" assert first_entry["message"] == @@ -2341,9 +2342,10 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2") response2 = json_response(conn2, 200) - [second_entry] = response2 + [second_entry] = response2["items"] - assert response2 |> length() == 1 + assert response2["total"] == 2 + assert response2["items"] |> length() == 1 assert second_entry["data"]["action"] == "relay_follow" assert second_entry["message"] == @@ -2387,9 +2389,9 @@ test "filters log by date", %{conn: conn, admin: admin} do ) response1 = json_response(conn1, 200) - [first_entry] = response1 + [first_entry] = response1["items"] - assert response1 |> length() == 1 + assert response1["total"] == 1 assert first_entry["data"]["action"] == "relay_unfollow" assert first_entry["message"] == @@ -2424,9 +2426,9 @@ test "returns log filtered by user", %{conn: conn, admin: admin, moderator: mode conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}") response1 = json_response(conn1, 200) - [first_entry] = response1 + [first_entry] = response1["items"] - assert response1 |> length() == 1 + assert response1["total"] == 1 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id end @@ -2446,9 +2448,9 @@ test "returns log filtered by search", %{conn: conn, moderator: moderator} do conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo") response1 = json_response(conn1, 200) - [first_entry] = response1 + [first_entry] = response1["items"] - assert response1 |> length() == 1 + assert response1["total"] == 1 assert get_in(first_entry, ["data", "message"]) == "@#{moderator.nickname} unfollowed relay: https://example.org/relay" From 35ef470d000c53e21c6f867d53ca3a83260d93b8 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 2 Sep 2019 12:15:21 +0100 Subject: [PATCH 027/272] truncate fields for remote users instead --- lib/pleroma/user/info.ex | 7 +++++++ test/user_test.exs | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 779bfbc18..0beb2f721 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -242,6 +242,7 @@ def set_keys(info, keys) do end def remote_user_creation(info, params) do + params = Map.put(params, "fields", Enum.map(params["fields"], &truncate_field/1)) info |> cast(params, [ :ap_enabled, @@ -326,6 +327,12 @@ defp valid_field?(%{"name" => name, "value" => value}) do defp valid_field?(_), do: false + defp truncate_field(%{"name" => name, "value" => value}) do + {name, _chopped} = String.split_at(name, Pleroma.Config.get([:instance, :account_field_name_length], 255)) + {value, _chopped} = String.split_at(value, Pleroma.Config.get([:instance, :account_field_value_length], 255)) + %{"name" => name, "value" => value} + end + @spec confirmation_changeset(Info.t(), keyword()) :: Changeset.t() def confirmation_changeset(info, opts) do need_confirmation? = Keyword.get(opts, :need_confirmation) diff --git a/test/user_test.exs b/test/user_test.exs index 2cbc1f525..68a469fe3 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1117,11 +1117,20 @@ test "get_public_key_for_ap_id fetches a user that's not in the db" do assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin") end - test "insert or update a user from given data" do - user = insert(:user, %{nickname: "nick@name.de"}) - data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname} + describe "insert or update a user from given data" do + test "with normal data" do + user = insert(:user, %{nickname: "nick@name.de"}) + data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname} - assert {:ok, %User{}} = User.insert_or_update_user(data) + assert {:ok, %User{}} = User.insert_or_update_user(data) + end + + test "with overly long fields" do + current_max_length = Pleroma.Config.get([:instance, :account_field_value_length], 255) + user = insert(:user, nickname: "nickname@supergood.domain") + data = %{ap_id: user.ap_id, info: %{ fields: [%{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)}] }} + assert {:ok, %User{}} = User.insert_or_update_user(data) + end end describe "per-user rich-text filtering" do From 05c935c3961e4c1a20c7713611920318d45d4b57 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 2 Sep 2019 12:15:40 +0100 Subject: [PATCH 028/272] mix format --- lib/pleroma/user/info.ex | 9 +++++++-- test/user_test.exs | 23 ++++++++++++++++------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 0beb2f721..ca1282d02 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -243,6 +243,7 @@ def set_keys(info, keys) do def remote_user_creation(info, params) do params = Map.put(params, "fields", Enum.map(params["fields"], &truncate_field/1)) + info |> cast(params, [ :ap_enabled, @@ -328,8 +329,12 @@ defp valid_field?(%{"name" => name, "value" => value}) do defp valid_field?(_), do: false defp truncate_field(%{"name" => name, "value" => value}) do - {name, _chopped} = String.split_at(name, Pleroma.Config.get([:instance, :account_field_name_length], 255)) - {value, _chopped} = String.split_at(value, Pleroma.Config.get([:instance, :account_field_value_length], 255)) + {name, _chopped} = + String.split_at(name, Pleroma.Config.get([:instance, :account_field_name_length], 255)) + + {value, _chopped} = + String.split_at(value, Pleroma.Config.get([:instance, :account_field_value_length], 255)) + %{"name" => name, "value" => value} end diff --git a/test/user_test.exs b/test/user_test.exs index 68a469fe3..0ca310331 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1119,17 +1119,26 @@ test "get_public_key_for_ap_id fetches a user that's not in the db" do describe "insert or update a user from given data" do test "with normal data" do - user = insert(:user, %{nickname: "nick@name.de"}) - data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname} + user = insert(:user, %{nickname: "nick@name.de"}) + data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname} - assert {:ok, %User{}} = User.insert_or_update_user(data) + assert {:ok, %User{}} = User.insert_or_update_user(data) end test "with overly long fields" do - current_max_length = Pleroma.Config.get([:instance, :account_field_value_length], 255) - user = insert(:user, nickname: "nickname@supergood.domain") - data = %{ap_id: user.ap_id, info: %{ fields: [%{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)}] }} - assert {:ok, %User{}} = User.insert_or_update_user(data) + current_max_length = Pleroma.Config.get([:instance, :account_field_value_length], 255) + user = insert(:user, nickname: "nickname@supergood.domain") + + data = %{ + ap_id: user.ap_id, + info: %{ + fields: [ + %{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)} + ] + } + } + + assert {:ok, %User{}} = User.insert_or_update_user(data) end end From d0f07e55d28d25684130cb1090d0bdbb48807548 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 2 Sep 2019 12:31:23 +0100 Subject: [PATCH 029/272] use atom key for fields --- lib/pleroma/user/info.ex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index ca1282d02..151e025de 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -242,7 +242,12 @@ def set_keys(info, keys) do end def remote_user_creation(info, params) do - params = Map.put(params, "fields", Enum.map(params["fields"], &truncate_field/1)) + params = + if Map.has_key?(params, :fields) do + Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1)) + else + params + end info |> cast(params, [ From e73685834c1797404c943f66417ffa30add87e04 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 2 Sep 2019 12:35:55 +0100 Subject: [PATCH 030/272] add mandatory fields for user update --- test/user_test.exs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/user_test.exs b/test/user_test.exs index 0ca310331..92a48f630 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1131,6 +1131,8 @@ test "with overly long fields" do data = %{ ap_id: user.ap_id, + name: user.name, + nickname: user.nickname, info: %{ fields: [ %{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)} From b49085c156a6a4449c95c2c315f6250317122735 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 2 Sep 2019 14:57:40 +0300 Subject: [PATCH 031/272] [#1149] Refactoring: GenServer workers renamed to daemons, `use Oban.Worker` moved to helper. --- config/config.exs | 2 +- lib/pleroma/application.ex | 4 ++-- .../activity_expiration_daemon.ex} | 2 +- .../digest_email_daemon.ex} | 2 +- .../scheduled_activity_daemon.ex} | 2 +- lib/pleroma/workers/activity_expiration_worker.ex | 7 +------ lib/pleroma/workers/background_worker.ex | 5 ----- lib/pleroma/workers/digest_emails_worker.ex | 7 +------ lib/pleroma/workers/mailer_worker.ex | 5 ----- lib/pleroma/workers/publisher_worker.ex | 5 ----- lib/pleroma/workers/receiver_worker.ex | 5 ----- lib/pleroma/workers/scheduled_activity_worker.ex | 7 +------ lib/pleroma/workers/subscriber_worker.ex | 5 ----- lib/pleroma/workers/transmogrifier_worker.ex | 5 ----- lib/pleroma/workers/web_pusher_worker.ex | 5 ----- lib/pleroma/workers/worker_helper.ex | 5 +++++ .../activity_expiration_daemon_test.exs} | 2 +- .../digest_email_daemon_test.exs} | 6 +++--- .../scheduled_activity_daemon_test.exs} | 4 ++-- 19 files changed, 20 insertions(+), 65 deletions(-) rename lib/pleroma/{activity_expiration_worker.ex => daemons/activity_expiration_daemon.ex} (96%) rename lib/pleroma/{digest_email_worker.ex => daemons/digest_email_daemon.ex} (96%) rename lib/pleroma/{scheduled_activity_worker.ex => daemons/scheduled_activity_daemon.ex} (96%) rename test/{activity_expiration_worker_test.exs => daemons/activity_expiration_daemon_test.exs} (86%) rename test/{web/digest_email_worker_test.exs => daemons/digest_email_daemon_test.exs} (88%) rename test/{scheduled_activity_worker_test.exs => daemons/scheduled_activity_daemon_test.exs} (82%) diff --git a/config/config.exs b/config/config.exs index 6fb4a0969..b742a650d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -54,7 +54,7 @@ scheduled_jobs = with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], true <- digest_config[:active] do - [{digest_config[:schedule], {Pleroma.DigestEmailWorker, :perform, []}}] + [{digest_config[:schedule], {Pleroma.Daemons.DigestEmailDaemon, :perform, []}}] else _ -> [] end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index f8f866dbd..0c27027a0 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -36,8 +36,8 @@ def start(_type, _args) do Pleroma.Emoji, Pleroma.Captcha, Pleroma.FlakeId, - Pleroma.ScheduledActivityWorker, - Pleroma.ActivityExpirationWorker + Pleroma.Daemons.ScheduledActivityDaemon, + Pleroma.Daemons.ActivityExpirationDaemon ] ++ cachex_children() ++ hackney_pool_children() ++ diff --git a/lib/pleroma/activity_expiration_worker.ex b/lib/pleroma/daemons/activity_expiration_daemon.ex similarity index 96% rename from lib/pleroma/activity_expiration_worker.ex rename to lib/pleroma/daemons/activity_expiration_daemon.ex index c0820c202..cab7628c4 100644 --- a/lib/pleroma/activity_expiration_worker.ex +++ b/lib/pleroma/daemons/activity_expiration_daemon.ex @@ -2,7 +2,7 @@ # Copyright © 2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.ActivityExpirationWorker do +defmodule Pleroma.Daemons.ActivityExpirationDaemon do alias Pleroma.Activity alias Pleroma.ActivityExpiration alias Pleroma.Config diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/daemons/digest_email_daemon.ex similarity index 96% rename from lib/pleroma/digest_email_worker.ex rename to lib/pleroma/daemons/digest_email_daemon.ex index 5be7cf26b..462ad2c55 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/daemons/digest_email_daemon.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.DigestEmailWorker do +defmodule Pleroma.Daemons.DigestEmailDaemon do alias Pleroma.Repo alias Pleroma.Workers.DigestEmailsWorker diff --git a/lib/pleroma/scheduled_activity_worker.ex b/lib/pleroma/daemons/scheduled_activity_daemon.ex similarity index 96% rename from lib/pleroma/scheduled_activity_worker.ex rename to lib/pleroma/daemons/scheduled_activity_daemon.ex index c41a542de..aee5f723a 100644 --- a/lib/pleroma/scheduled_activity_worker.ex +++ b/lib/pleroma/daemons/scheduled_activity_daemon.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.ScheduledActivityWorker do +defmodule Pleroma.Daemons.ScheduledActivityDaemon do @moduledoc """ Sends scheduled activities to the job queue. """ diff --git a/lib/pleroma/workers/activity_expiration_worker.ex b/lib/pleroma/workers/activity_expiration_worker.ex index 60dd3feba..4e3e4195f 100644 --- a/lib/pleroma/workers/activity_expiration_worker.ex +++ b/lib/pleroma/workers/activity_expiration_worker.ex @@ -3,11 +3,6 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.ActivityExpirationWorker do - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "activity_expiration", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "activity_expiration" @impl Oban.Worker @@ -18,6 +13,6 @@ def perform( }, _job ) do - Pleroma.ActivityExpirationWorker.perform(:execute, activity_expiration_id) + Pleroma.Daemons.ActivityExpirationDaemon.perform(:execute, activity_expiration_id) end end diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index b9aef3a92..082f20ab7 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -8,11 +8,6 @@ defmodule Pleroma.Workers.BackgroundWorker do alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy alias Pleroma.Web.OAuth.Token.CleanWorker - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "background", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "background" @impl Oban.Worker diff --git a/lib/pleroma/workers/digest_emails_worker.ex b/lib/pleroma/workers/digest_emails_worker.ex index ca073ce67..3e5a836d0 100644 --- a/lib/pleroma/workers/digest_emails_worker.ex +++ b/lib/pleroma/workers/digest_emails_worker.ex @@ -5,17 +5,12 @@ defmodule Pleroma.Workers.DigestEmailsWorker do alias Pleroma.User - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "digest_emails", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "digest_emails" @impl Oban.Worker def perform(%{"op" => "digest_email", "user_id" => user_id}, _job) do user_id |> User.get_cached_by_id() - |> Pleroma.DigestEmailWorker.perform() + |> Pleroma.Daemons.DigestEmailDaemon.perform() end end diff --git a/lib/pleroma/workers/mailer_worker.ex b/lib/pleroma/workers/mailer_worker.ex index a4bd54a6c..1b7a0eb3e 100644 --- a/lib/pleroma/workers/mailer_worker.ex +++ b/lib/pleroma/workers/mailer_worker.ex @@ -3,11 +3,6 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.MailerWorker do - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "mailer", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "mailer" @impl Oban.Worker diff --git a/lib/pleroma/workers/publisher_worker.ex b/lib/pleroma/workers/publisher_worker.ex index a3ac22635..455f7fc7e 100644 --- a/lib/pleroma/workers/publisher_worker.ex +++ b/lib/pleroma/workers/publisher_worker.ex @@ -6,11 +6,6 @@ defmodule Pleroma.Workers.PublisherWorker do alias Pleroma.Activity alias Pleroma.Web.Federator - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "federator_outgoing", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "federator_outgoing" def backoff(attempt) when is_integer(attempt) do diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex index 3cc415ce4..83d528a66 100644 --- a/lib/pleroma/workers/receiver_worker.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -5,11 +5,6 @@ defmodule Pleroma.Workers.ReceiverWorker do alias Pleroma.Web.Federator - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "federator_incoming", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "federator_incoming" @impl Oban.Worker diff --git a/lib/pleroma/workers/scheduled_activity_worker.ex b/lib/pleroma/workers/scheduled_activity_worker.ex index 936bb64d3..ca7d53af1 100644 --- a/lib/pleroma/workers/scheduled_activity_worker.ex +++ b/lib/pleroma/workers/scheduled_activity_worker.ex @@ -3,15 +3,10 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.ScheduledActivityWorker do - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "scheduled_activities", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "scheduled_activities" @impl Oban.Worker def perform(%{"op" => "execute", "activity_id" => activity_id}, _job) do - Pleroma.ScheduledActivityWorker.perform(:execute, activity_id) + Pleroma.Daemons.ScheduledActivityDaemon.perform(:execute, activity_id) end end diff --git a/lib/pleroma/workers/subscriber_worker.ex b/lib/pleroma/workers/subscriber_worker.ex index 4fb994554..fc490e300 100644 --- a/lib/pleroma/workers/subscriber_worker.ex +++ b/lib/pleroma/workers/subscriber_worker.ex @@ -7,11 +7,6 @@ defmodule Pleroma.Workers.SubscriberWorker do alias Pleroma.Web.Federator alias Pleroma.Web.Websub - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "federator_outgoing", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "federator_outgoing" @impl Oban.Worker diff --git a/lib/pleroma/workers/transmogrifier_worker.ex b/lib/pleroma/workers/transmogrifier_worker.ex index 6fecc2bf9..b581a2f86 100644 --- a/lib/pleroma/workers/transmogrifier_worker.ex +++ b/lib/pleroma/workers/transmogrifier_worker.ex @@ -5,11 +5,6 @@ defmodule Pleroma.Workers.TransmogrifierWorker do alias Pleroma.User - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "transmogrifier", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "transmogrifier" @impl Oban.Worker diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex index 4c2591a5c..bea2baffb 100644 --- a/lib/pleroma/workers/web_pusher_worker.ex +++ b/lib/pleroma/workers/web_pusher_worker.ex @@ -6,11 +6,6 @@ defmodule Pleroma.Workers.WebPusherWorker do alias Pleroma.Notification alias Pleroma.Repo - # Note: `max_attempts` is intended to be overridden in `new/2` call - use Oban.Worker, - queue: "web_push", - max_attempts: 1 - use Pleroma.Workers.WorkerHelper, queue: "web_push" @impl Oban.Worker diff --git a/lib/pleroma/workers/worker_helper.ex b/lib/pleroma/workers/worker_helper.ex index b12f198d4..358efa14a 100644 --- a/lib/pleroma/workers/worker_helper.ex +++ b/lib/pleroma/workers/worker_helper.ex @@ -27,6 +27,11 @@ defmacro __using__(opts) do queue = Keyword.fetch!(opts, :queue) quote do + # Note: `max_attempts` is intended to be overridden in `new/2` call + use Oban.Worker, + queue: unquote(queue), + max_attempts: 1 + def enqueue(op, params, worker_args \\ []) do params = Map.merge(%{"op" => op}, params) queue_atom = String.to_atom(unquote(queue)) diff --git a/test/activity_expiration_worker_test.exs b/test/daemons/activity_expiration_daemon_test.exs similarity index 86% rename from test/activity_expiration_worker_test.exs rename to test/daemons/activity_expiration_daemon_test.exs index 939d912f1..31f4a70a6 100644 --- a/test/activity_expiration_worker_test.exs +++ b/test/daemons/activity_expiration_daemon_test.exs @@ -10,7 +10,7 @@ defmodule Pleroma.ActivityExpirationWorkerTest do test "deletes an activity" do activity = insert(:note_activity) expiration = insert(:expiration_in_the_past, %{activity_id: activity.id}) - Pleroma.ActivityExpirationWorker.perform(:execute, expiration.id) + Pleroma.Daemons.ActivityExpirationDaemon.perform(:execute, expiration.id) refute Repo.get(Activity, activity.id) end diff --git a/test/web/digest_email_worker_test.exs b/test/daemons/digest_email_daemon_test.exs similarity index 88% rename from test/web/digest_email_worker_test.exs rename to test/daemons/digest_email_daemon_test.exs index 5dfd920fa..3168f3b9a 100644 --- a/test/web/digest_email_worker_test.exs +++ b/test/daemons/digest_email_daemon_test.exs @@ -2,11 +2,11 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.DigestEmailWorkerTest do +defmodule Pleroma.DigestEmailDaemonTest do use Pleroma.DataCase import Pleroma.Factory - alias Pleroma.DigestEmailWorker + alias Pleroma.Daemons.DigestEmailDaemon alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -23,7 +23,7 @@ test "it sends digest emails" do User.switch_email_notifications(user2, "digest", true) CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}!"}) - DigestEmailWorker.perform() + DigestEmailDaemon.perform() ObanHelpers.perform_all() # Performing job(s) enqueued at previous step ObanHelpers.perform_all() diff --git a/test/scheduled_activity_worker_test.exs b/test/daemons/scheduled_activity_daemon_test.exs similarity index 82% rename from test/scheduled_activity_worker_test.exs rename to test/daemons/scheduled_activity_daemon_test.exs index e3ad1244e..32820b2b7 100644 --- a/test/scheduled_activity_worker_test.exs +++ b/test/daemons/scheduled_activity_daemon_test.exs @@ -2,7 +2,7 @@ # Copyright © 2017-2018 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.ScheduledActivityWorkerTest do +defmodule Pleroma.ScheduledActivityDaemonTest do use Pleroma.DataCase alias Pleroma.ScheduledActivity import Pleroma.Factory @@ -10,7 +10,7 @@ defmodule Pleroma.ScheduledActivityWorkerTest do test "creates a status from the scheduled activity" do user = insert(:user) scheduled_activity = insert(:scheduled_activity, user: user, params: %{status: "hi"}) - Pleroma.ScheduledActivityWorker.perform(:execute, scheduled_activity.id) + Pleroma.Daemons.ScheduledActivityDaemon.perform(:execute, scheduled_activity.id) refute Repo.get(ScheduledActivity, scheduled_activity.id) activity = Repo.all(Pleroma.Activity) |> Enum.find(&(&1.actor == user.ap_id)) From 8cbad5500cefbba1e0bb67604960fc331b75b498 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 4 Sep 2019 15:25:12 +0300 Subject: [PATCH 032/272] add tests for activity_pub/utils.ex --- lib/pleroma/user.ex | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 12 +- lib/pleroma/web/activity_pub/utils.ex | 298 +++++++++---------- test/web/activity_pub/utils_test.exs | 232 ++++++++++++++- 4 files changed, 371 insertions(+), 172 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 29fd6d2ea..424ed772f 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -147,6 +147,7 @@ def get_cached_follow_state(user, target) do Cachex.fetch!(:user_cache, key, fn _ -> {:commit, follow_state(user, target)} end) end + @spec set_follow_state_cache(String.t(), String.t(), String.t()) :: {:ok | :error, boolean()} def set_follow_state_cache(user_ap_id, target_ap_id, state) do Cachex.put( :user_cache, diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index eeb826814..39b46a595 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -435,6 +435,7 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru end end + @spec block(User.t(), User.t(), String.t() | nil, boolean) :: {:ok, Activity.t() | nil} def block(blocker, blocked, activity_id \\ nil, local \\ true) do outgoing_blocks = Config.get([:activitypub, :outgoing_blocks]) unfollow_blocked = Config.get([:activitypub, :unfollow_blocked]) @@ -463,10 +464,11 @@ def unblock(blocker, blocked, activity_id \\ nil, local \\ true) do end end + @spec flag(map()) :: {:ok, Activity.t()} | any def flag( %{ actor: actor, - context: context, + context: _context, account: account, statuses: statuses, content: content @@ -478,14 +480,6 @@ def flag( additional = params[:additional] || %{} - params = %{ - actor: actor, - context: context, - account: account, - statuses: statuses, - content: content - } - additional = if forward do Map.merge(additional, %{"to" => [], "cc" => [account.ap_id]}) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index c9c0c3763..cf82d1a9b 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -33,50 +33,40 @@ def normalize_params(params) do Map.put(params, "actor", get_ap_id(params["actor"])) end - def determine_explicit_mentions(%{"tag" => tag} = _object) when is_list(tag) do - tag - |> Enum.filter(fn x -> is_map(x) end) - |> Enum.filter(fn x -> x["type"] == "Mention" end) - |> Enum.map(fn x -> x["href"] end) + @spec determine_explicit_mentions(map()) :: map() + def determine_explicit_mentions(%{"tag" => tag} = _) when is_list(tag) do + Enum.flat_map(tag, fn + %{"type" => "Mention", "href" => href} -> [href] + _ -> [] + end) end def determine_explicit_mentions(%{"tag" => tag} = object) when is_map(tag) do - Map.put(object, "tag", [tag]) + object + |> Map.put("tag", [tag]) |> determine_explicit_mentions() end def determine_explicit_mentions(_), do: [] + @spec recipient_in_collection(any(), any()) :: boolean() defp recipient_in_collection(ap_id, coll) when is_binary(coll), do: ap_id == coll defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll defp recipient_in_collection(_, _), do: false + @spec recipient_in_message(User.t(), User.t(), map()) :: boolean() def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params) do + addresses = [params["to"], params["cc"], params["bto"], params["bcc"]] + cond do - recipient_in_collection(ap_id, params["to"]) -> - true - - recipient_in_collection(ap_id, params["cc"]) -> - true - - recipient_in_collection(ap_id, params["bto"]) -> - true - - recipient_in_collection(ap_id, params["bcc"]) -> - true - + Enum.any?(addresses, &recipient_in_collection(ap_id, &1)) -> true # if the message is unaddressed at all, then assume it is directly addressed # to the recipient - !params["to"] && !params["cc"] && !params["bto"] && !params["bcc"] -> - true - + Enum.all?(addresses, &is_nil(&1)) -> true # if the message is sent from somebody the user is following, then assume it # is addressed to the recipient - User.following?(recipient, actor) -> - true - - true -> - false + User.following?(recipient, actor) -> true + true -> false end end @@ -188,53 +178,58 @@ def maybe_federate(_), do: :ok Adds an id and a published data if they aren't there, also adds it to an included object """ - def lazy_put_activity_defaults(map, fake \\ false) do - map = - unless fake do - %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) + @spec lazy_put_activity_defaults(map(), boolean) :: map() + def lazy_put_activity_defaults(map, fake \\ false) - map - |> Map.put_new_lazy("id", &generate_activity_id/0) - |> Map.put_new_lazy("published", &make_date/0) - |> Map.put_new("context", context) - |> Map.put_new("context_id", context_id) - else - map - |> Map.put_new("id", "pleroma:fakeid") - |> Map.put_new_lazy("published", &make_date/0) - |> Map.put_new("context", "pleroma:fakecontext") - |> Map.put_new("context_id", -1) - end + def lazy_put_activity_defaults(map, true) do + map + |> Map.put_new("id", "pleroma:fakeid") + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", "pleroma:fakecontext") + |> Map.put_new("context_id", -1) + |> lazy_put_object_defaults(true) + end - if is_map(map["object"]) do - object = lazy_put_object_defaults(map["object"], map, fake) - %{map | "object" => object} - else + def lazy_put_activity_defaults(map, _fake) do + %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) + + map + |> Map.put_new_lazy("id", &generate_activity_id/0) + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", context) + |> Map.put_new("context_id", context_id) + |> lazy_put_object_defaults(false) + end + + # Adds an id and published date if they aren't there. + # + @spec lazy_put_object_defaults(map(), boolean()) :: map() + defp lazy_put_object_defaults(%{"object" => map} = activity, true) + when is_map(map) do + object = map - end + |> Map.put_new("id", "pleroma:fake_object_id") + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", activity["context"]) + |> Map.put_new("context_id", activity["context_id"]) + |> Map.put_new("fake", true) + + %{activity | "object" => object} end - @doc """ - Adds an id and published date if they aren't there. - """ - def lazy_put_object_defaults(map, activity \\ %{}, fake) + defp lazy_put_object_defaults(%{"object" => map} = activity, _) + when is_map(map) do + object = + map + |> Map.put_new_lazy("id", &generate_object_id/0) + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", activity["context"]) + |> Map.put_new("context_id", activity["context_id"]) - def lazy_put_object_defaults(map, activity, true = _fake) do - map - |> Map.put_new_lazy("published", &make_date/0) - |> Map.put_new("id", "pleroma:fake_object_id") - |> Map.put_new("context", activity["context"]) - |> Map.put_new("fake", true) - |> Map.put_new("context_id", activity["context_id"]) + %{activity | "object" => object} end - def lazy_put_object_defaults(map, activity, _fake) do - map - |> Map.put_new_lazy("id", &generate_object_id/0) - |> Map.put_new_lazy("published", &make_date/0) - |> Map.put_new("context", activity["context"]) - |> Map.put_new("context_id", activity["context_id"]) - end + defp lazy_put_object_defaults(activity, _), do: activity @doc """ Inserts a full object if it is contained in an activity. @@ -356,23 +351,30 @@ defp fetch_likes(object) do @doc """ Updates a follow activity's state (for locked accounts). """ + @spec update_follow_state_for_all(Activity.t(), String.t()) :: {:ok, Activity} | {:error, any()} def update_follow_state_for_all( %Activity{data: %{"actor" => actor, "object" => object}} = activity, state ) do - try do - Ecto.Adapters.SQL.query!( - Repo, - "UPDATE activities SET data = jsonb_set(data, '{state}', $1) WHERE data->>'type' = 'Follow' AND data->>'actor' = $2 AND data->>'object' = $3 AND data->>'state' = 'pending'", - [state, actor, object] + query = + from(activity in Activity, + where: fragment("data->>'type' = 'Follow'"), + where: fragment("data->>'state' = 'pending'"), + where: fragment("data->>'actor' = ?", ^actor), + where: fragment("data->>'object' = ?", ^object), + update: [ + set: [ + data: fragment("jsonb_set(data, '{state}', ?)", ^state) + ] + ] ) - User.set_follow_state_cache(actor, object, state) - activity = Activity.get_by_id(activity.id) + with {_, _} <- Repo.update_all(query, []), + {_, _} <- User.set_follow_state_cache(actor, object, state), + %Activity{} = activity <- Activity.get_by_id(activity.id) do {:ok, activity} - rescue - e -> - {:error, e} + else + e -> {:error, e} end end @@ -380,9 +382,7 @@ def update_follow_state( %Activity{data: %{"actor" => actor, "object" => object}} = activity, state ) do - with new_data <- - activity.data - |> Map.put("state", state), + with new_data <- Map.put(activity.data, "state", state), changeset <- Changeset.change(activity, data: new_data), {:ok, activity} <- Repo.update(changeset), _ <- User.set_follow_state_cache(actor, object, state) do @@ -411,27 +411,17 @@ def make_follow_data( def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do query = - from( - activity in Activity, - where: - fragment( - "? ->> 'type' = 'Follow'", - activity.data - ), - where: activity.actor == ^follower_id, - # this is to use the index - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^followed_id - ), - order_by: [fragment("? desc nulls last", activity.id)], - limit: 1 - ) + follower_id + |> Activity.Queries.by_actor() + |> Activity.Queries.by_type("Follow") + |> Activity.Queries.by_object_id(followed_id) + |> Activity.Queries.limit(1) - Repo.one(query) + from( + activity in query, + order_by: [fragment("? desc nulls last", activity.id)] + ) + |> Repo.one() end #### Announce-related helpers @@ -439,23 +429,14 @@ def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do @doc """ Retruns an existing announce activity if the notice has already been announced """ + @spec get_existing_announce(String.t(), map()) :: Activity.t() | nil def get_existing_announce(actor, %{data: %{"id" => id}}) do - query = - from( - activity in Activity, - where: activity.actor == ^actor, - # this is to use the index - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^id - ), - where: fragment("(?)->>'type' = 'Announce'", activity.data) - ) - - Repo.one(query) + actor + |> Activity.Queries.by_actor() + |> Activity.Queries.by_type("Announce") + |> Activity.Queries.by_object_id(id) + |> Activity.Queries.limit(1) + |> Repo.one() end @doc """ @@ -531,31 +512,35 @@ def make_unlike_data( |> maybe_put("id", activity_id) end + @spec add_announce_to_object(Activity.t(), Object.t()) :: + {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_announce_to_object( - %Activity{ - data: %{"actor" => actor, "cc" => [Pleroma.Constants.as_public()]} - }, + %Activity{data: %{"actor" => actor, "cc" => [Pleroma.Constants.as_public()]}}, object ) do - announcements = - if is_list(object.data["announcements"]), do: object.data["announcements"], else: [] + announcements = fetch_announcements(object) - with announcements <- [actor | announcements] |> Enum.uniq() do + with announcements <- Enum.uniq([actor | announcements]) do update_element_in_object("announcement", announcements, object) end end def add_announce_to_object(_, object), do: {:ok, object} + @spec remove_announce_from_object(Activity.t(), Object.t()) :: + {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do - announcements = - if is_list(object.data["announcements"]), do: object.data["announcements"], else: [] - - with announcements <- announcements |> List.delete(actor) do + with announcements <- List.delete(fetch_announcements(object), actor) do update_element_in_object("announcement", announcements, object) end end + defp fetch_announcements(%{data: %{"announcements" => announcements}} = _) + when is_list(announcements), + do: announcements + + defp fetch_announcements(_), do: [] + #### Unfollow-related helpers def make_unfollow_data(follower, followed, follow_activity, activity_id) do @@ -569,29 +554,20 @@ def make_unfollow_data(follower, followed, follow_activity, activity_id) do end #### Block-related helpers + @spec fetch_latest_block(User.t(), User.t()) :: Activity.t() | nil def fetch_latest_block(%User{ap_id: blocker_id}, %User{ap_id: blocked_id}) do query = - from( - activity in Activity, - where: - fragment( - "? ->> 'type' = 'Block'", - activity.data - ), - where: activity.actor == ^blocker_id, - # this is to use the index - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^blocked_id - ), - order_by: [fragment("? desc nulls last", activity.id)], - limit: 1 - ) + blocker_id + |> Activity.Queries.by_actor() + |> Activity.Queries.by_type("Block") + |> Activity.Queries.by_object_id(blocked_id) + |> Activity.Queries.limit(1) - Repo.one(query) + from( + activity in query, + order_by: [fragment("? desc nulls last", activity.id)] + ) + |> Repo.one() end def make_block_data(blocker, blocked, activity_id) do @@ -631,28 +607,32 @@ def make_create_data(params, additional) do end #### Flag-related helpers - - def make_flag_data(params, additional) do - status_ap_ids = - Enum.map(params.statuses || [], fn - %Activity{} = act -> act.data["id"] - act when is_map(act) -> act["id"] - act when is_binary(act) -> act - end) - - object = [params.account.ap_id] ++ status_ap_ids - + @spec make_flag_data(map(), map()) :: map() + def make_flag_data(%{actor: actor, context: context, content: content} = params, additional) do %{ "type" => "Flag", - "actor" => params.actor.ap_id, - "content" => params.content, - "object" => object, - "context" => params.context, + "actor" => actor.ap_id, + "content" => content, + "object" => build_flag_object(params), + "context" => context, "state" => "open" } |> Map.merge(additional) end + def make_flag_data(_, _), do: %{} + + defp build_flag_object(%{account: account, statuses: statuses} = _) do + [account.ap_id] ++ + Enum.map(statuses || [], fn + %Activity{} = act -> act.data["id"] + act when is_map(act) -> act["id"] + act when is_binary(act) -> act + end) + end + + defp build_flag_object(_), do: [] + @doc """ Fetches the OrderedCollection/OrderedCollectionPage from `from`, limiting the amount of pages fetched after the first one to `pages_left` pages. diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index eb429b2c4..b1c1d6f71 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -87,6 +87,18 @@ test "works with an object that has only IR tags" do assert Utils.determine_explicit_mentions(object) == [] end + + test "works with an object has tags as map" do + object = %{ + "tag" => %{ + "type" => "Mention", + "href" => "https://example.com/~alyssa", + "name" => "Alyssa P. Hacker" + } + } + + assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"] + end end describe "make_unlike_data/3" do @@ -300,8 +312,8 @@ test "updates the state of all Follow activities with the same actor and object" {:ok, follow_activity_two} = Utils.update_follow_state_for_all(follow_activity_two, "accept") - assert Repo.get(Activity, follow_activity.id).data["state"] == "accept" - assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept" + assert refresh_record(follow_activity).data["state"] == "accept" + assert refresh_record(follow_activity_two).data["state"] == "accept" end end @@ -323,8 +335,8 @@ test "updates the state of the given follow activity" do {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject") - assert Repo.get(Activity, follow_activity.id).data["state"] == "pending" - assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject" + assert refresh_record(follow_activity).data["state"] == "pending" + assert refresh_record(follow_activity_two).data["state"] == "reject" end end @@ -401,4 +413,216 @@ test "fetches existing like" do assert ^like_activity = Utils.get_existing_like(user.ap_id, object) end end + + describe "get_get_existing_announce/2" do + test "returns nil if announce not found" do + actor = insert(:user) + refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}}) + end + + test "fetches existing announce" do + note_activity = insert(:note_activity) + assert object = Object.normalize(note_activity) + actor = insert(:user) + + {:ok, announce, _object} = ActivityPub.announce(actor, object) + assert Utils.get_existing_announce(actor.ap_id, object) == announce + end + end + + describe "fetch_latest_block/2" do + test "fetches last block activities" do + user1 = insert(:user) + user2 = insert(:user) + + assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2) + assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2) + assert {:ok, %Activity{} = activity} = ActivityPub.block(user1, user2) + + assert Utils.fetch_latest_block(user1, user2) == activity + end + end + + describe "recipient_in_message/3" do + test "returns true when recipient in `to`" do + recipient = insert(:user) + actor = insert(:user) + assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id}) + + assert Utils.recipient_in_message( + recipient, + actor, + %{"to" => [recipient.ap_id], "cc" => ""} + ) + end + + test "returns true when recipient in `cc`" do + recipient = insert(:user) + actor = insert(:user) + assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id}) + + assert Utils.recipient_in_message( + recipient, + actor, + %{"cc" => [recipient.ap_id], "to" => ""} + ) + end + + test "returns true when recipient in `bto`" do + recipient = insert(:user) + actor = insert(:user) + assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id}) + + assert Utils.recipient_in_message( + recipient, + actor, + %{"bcc" => "", "bto" => [recipient.ap_id]} + ) + end + + test "returns true when recipient in `bcc`" do + recipient = insert(:user) + actor = insert(:user) + assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id}) + + assert Utils.recipient_in_message( + recipient, + actor, + %{"bto" => "", "bcc" => [recipient.ap_id]} + ) + end + + test "returns true when message without addresses fields" do + recipient = insert(:user) + actor = insert(:user) + assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id}) + + assert Utils.recipient_in_message( + recipient, + actor, + %{"btod" => "", "bccc" => [recipient.ap_id]} + ) + end + + test "returns false" do + recipient = insert(:user) + actor = insert(:user) + refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"}) + end + end + + describe "lazy_put_activity_defaults/2" do + test "returns map with id and published data" do + note_activity = insert(:note_activity) + object = Object.normalize(note_activity) + res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]}) + assert res["context"] == object.data["id"] + assert res["context_id"] == object.id + assert res["id"] + assert res["published"] + end + + test "returns map with fake id and published data" do + assert %{ + "context" => "pleroma:fakecontext", + "context_id" => -1, + "id" => "pleroma:fakeid", + "published" => _ + } = Utils.lazy_put_activity_defaults(%{}, true) + end + + test "returns activity data with object" do + note_activity = insert(:note_activity) + object = Object.normalize(note_activity) + + res = + Utils.lazy_put_activity_defaults(%{ + "context" => object.data["id"], + "object" => %{} + }) + + assert res["context"] == object.data["id"] + assert res["context_id"] == object.id + assert res["id"] + assert res["published"] + assert res["object"]["id"] + assert res["object"]["published"] + assert res["object"]["context"] == object.data["id"] + assert res["object"]["context_id"] == object.id + end + end + + describe "make_flag_data" do + test "returns empty map when params is invalid" do + assert Utils.make_flag_data(%{}, %{}) == %{} + end + + test "returns map with Flag object" do + reporter = insert(:user) + target_account = insert(:user) + {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"}) + context = Utils.generate_context_id() + content = "foobar" + + target_ap_id = target_account.ap_id + activity_ap_id = activity.data["id"] + + res = + Utils.make_flag_data( + %{ + actor: reporter, + context: context, + account: target_account, + statuses: [%{"id" => activity.data["id"]}], + content: content + }, + %{} + ) + + assert %{ + "type" => "Flag", + "content" => ^content, + "context" => ^context, + "object" => [^target_ap_id, ^activity_ap_id], + "state" => "open" + } = res + end + end + + describe "add_announce_to_object/2" do + test "adds actor to announcement" do + user = insert(:user) + object = insert(:note) + + activity = + insert(:note_activity, + data: %{ + "actor" => user.ap_id, + "cc" => [Pleroma.Constants.as_public()] + } + ) + + assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object) + assert updated_object.data["announcements"] == [user.ap_id] + assert updated_object.data["announcement_count"] == 1 + end + end + + describe "remove_announce_from_object/2" do + test "removes actor from announcements" do + user = insert(:user) + user2 = insert(:user) + + object = + insert(:note, + data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2} + ) + + activity = insert(:note_activity, data: %{"actor" => user.ap_id}) + + assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object) + assert updated_object.data["announcements"] == [user2.ap_id] + assert updated_object.data["announcement_count"] == 1 + end + end end From a890451187f0b1507be96ccf144b18fdb8294dd8 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 4 Sep 2019 17:42:27 +0300 Subject: [PATCH 033/272] fetch_announcements -> take_announcements --- lib/pleroma/web/activity_pub/utils.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index cf82d1a9b..0d87b9220 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -518,7 +518,7 @@ def add_announce_to_object( %Activity{data: %{"actor" => actor, "cc" => [Pleroma.Constants.as_public()]}}, object ) do - announcements = fetch_announcements(object) + announcements = take_announcements(object) with announcements <- Enum.uniq([actor | announcements]) do update_element_in_object("announcement", announcements, object) @@ -530,16 +530,16 @@ def add_announce_to_object(_, object), do: {:ok, object} @spec remove_announce_from_object(Activity.t(), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do - with announcements <- List.delete(fetch_announcements(object), actor) do + with announcements <- List.delete(take_announcements(object), actor) do update_element_in_object("announcement", announcements, object) end end - defp fetch_announcements(%{data: %{"announcements" => announcements}} = _) + defp take_announcements(%{data: %{"announcements" => announcements}} = _) when is_list(announcements), do: announcements - defp fetch_announcements(_), do: [] + defp take_announcements(_), do: [] #### Unfollow-related helpers From 2975da284b75c846a99a56ce70a91ebc3cc43f33 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Wed, 4 Sep 2019 15:45:40 +0100 Subject: [PATCH 034/272] truncate remote user bio/display name --- lib/pleroma/user.ex | 16 +++++++++++++++- test/user_test.exs | 45 +++++++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 29fd6d2ea..87e56b5b4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -174,11 +174,25 @@ def following_count(%User{} = user) do |> Repo.aggregate(:count, :id) end + defp truncate_if_exists(params, key, max_length) do + if Map.has_key?(params, key) do + {value, _chopped} = String.split_at(params[key], max_length) + Map.put(params, key, value) + else + params + end + end + def remote_user_creation(params) do bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) - params = Map.put(params, :info, params[:info] || %{}) + params = + params + |> Map.put(:info, params[:info] || %{}) + |> truncate_if_exists(:name, name_limit) + |> truncate_if_exists(:bio, bio_limit) + info_cng = User.Info.remote_user_creation(%User.Info{}, params[:info]) changes = diff --git a/test/user_test.exs b/test/user_test.exs index 92a48f630..45f998ff8 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -570,22 +570,6 @@ test "it has required fields" do refute cs.valid? end) end - - test "it restricts some sizes" do - bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) - name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) - - [bio: bio_limit, name: name_limit] - |> Enum.each(fn {field, size} -> - string = String.pad_leading(".", size) - cs = User.remote_user_creation(Map.put(@valid_remote, field, string)) - assert cs.valid? - - string = String.pad_leading(".", size + 1) - cs = User.remote_user_creation(Map.put(@valid_remote, field, string)) - refute cs.valid? - end) - end end describe "followers and friends" do @@ -1142,6 +1126,35 @@ test "with overly long fields" do assert {:ok, %User{}} = User.insert_or_update_user(data) end + + test "with an overly long bio" do + current_max_length = Pleroma.Config.get([:instance, :user_bio_length], 5000) + user = insert(:user, nickname: "nickname@supergood.domain") + + data = %{ + ap_id: user.ap_id, + name: user.name, + nickname: user.nickname, + bio: String.duplicate("h", current_max_length + 1), + info: %{} + } + + assert {:ok, %User{}} = User.insert_or_update_user(data) + end + + test "with an overly long display name" do + current_max_length = Pleroma.Config.get([:instance, :user_name_length], 100) + user = insert(:user, nickname: "nickname@supergood.domain") + + data = %{ + ap_id: user.ap_id, + name: String.duplicate("h", current_max_length + 1), + nickname: user.nickname, + info: %{} + } + + assert {:ok, %User{}} = User.insert_or_update_user(data) + end end describe "per-user rich-text filtering" do From cb99cfcc65f57f0044117ebd12d040488343d9ef Mon Sep 17 00:00:00 2001 From: Sadposter Date: Wed, 4 Sep 2019 15:57:42 +0100 Subject: [PATCH 035/272] don't try to truncate non-strings --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 87e56b5b4..e2ebce6fc 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -175,7 +175,7 @@ def following_count(%User{} = user) do end defp truncate_if_exists(params, key, max_length) do - if Map.has_key?(params, key) do + if Map.has_key?(params, key) and is_binary(params[key]) do {value, _chopped} = String.split_at(params[key], max_length) Map.put(params, key, value) else From af746fa4a814dbacd4fe4a3e58b1ee1732363d22 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 4 Sep 2019 20:08:13 +0300 Subject: [PATCH 036/272] Return total for reports --- CHANGELOG.md | 3 ++- docs/api/admin_api.md | 1 + lib/pleroma/web/admin_api/admin_api_controller.ex | 6 ++---- lib/pleroma/web/admin_api/views/report_view.ex | 3 ++- test/web/admin_api/admin_api_controller_test.exs | 8 ++++++++ 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a414ba5e0..942605f28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Unsubscribe followers when they unfollow a user - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) - Improve digest email template -– Pagination: (optional) return `total` alongside with `items` when paginating +- Pagination: (optional) return `total` alongside with `items` when paginating +- Admin API: Return `total` when querying for reports ### Fixed - Following from Osada diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index d79c342be..5a090c720 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -313,6 +313,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ```json { + "total" : 1, "reports": [ { "account": { diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 544b9d7d8..2a1cc59e5 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -442,11 +442,9 @@ def list_reports(conn, params) do params |> Map.put("type", "Flag") |> Map.put("skip_preload", true) + |> Map.put("total", true) - reports = - [] - |> ActivityPub.fetch_activities(params) - |> Enum.reverse() + reports = ActivityPub.fetch_activities([], params) conn |> put_view(ReportView) diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index a25f3f1fe..0b8745b2e 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -12,7 +12,8 @@ defmodule Pleroma.Web.AdminAPI.ReportView do def render("index.json", %{reports: reports}) do %{ - reports: render_many(reports, __MODULE__, "show.json", as: :report) + reports: render_many(reports[:items], __MODULE__, "show.json", as: :report), + total: reports[:total] } end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 4e2c27431..b1ddd898b 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1309,6 +1309,7 @@ test "returns empty response when no reports created", %{conn: conn} do |> json_response(:ok) assert Enum.empty?(response["reports"]) + assert response["total"] == 0 end test "returns reports", %{conn: conn} do @@ -1331,6 +1332,8 @@ test "returns reports", %{conn: conn} do assert length(response["reports"]) == 1 assert report["id"] == report_id + + assert response["total"] == 1 end test "returns reports with specified state", %{conn: conn} do @@ -1364,6 +1367,8 @@ test "returns reports with specified state", %{conn: conn} do assert length(response["reports"]) == 1 assert open_report["id"] == first_report_id + assert response["total"] == 1 + response = conn |> get("/api/pleroma/admin/reports", %{ @@ -1376,6 +1381,8 @@ test "returns reports with specified state", %{conn: conn} do assert length(response["reports"]) == 1 assert closed_report["id"] == second_report_id + assert response["total"] == 1 + response = conn |> get("/api/pleroma/admin/reports", %{ @@ -1384,6 +1391,7 @@ test "returns reports with specified state", %{conn: conn} do |> json_response(:ok) assert Enum.empty?(response["reports"]) + assert response["total"] == 0 end test "returns 403 when requested by a non-admin" do From 8306078de1abade082f932cda5b8d9297bdcdc80 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 4 Sep 2019 17:31:14 +0000 Subject: [PATCH 037/272] Apply suggestion to lib/pleroma/web/activity_pub/utils.ex --- lib/pleroma/web/activity_pub/utils.ex | 33 +++++++++++---------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 0d87b9220..2de02f607 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -356,26 +356,19 @@ def update_follow_state_for_all( %Activity{data: %{"actor" => actor, "object" => object}} = activity, state ) do - query = - from(activity in Activity, - where: fragment("data->>'type' = 'Follow'"), - where: fragment("data->>'state' = 'pending'"), - where: fragment("data->>'actor' = ?", ^actor), - where: fragment("data->>'object' = ?", ^object), - update: [ - set: [ - data: fragment("jsonb_set(data, '{state}', ?)", ^state) - ] - ] - ) - - with {_, _} <- Repo.update_all(query, []), - {_, _} <- User.set_follow_state_cache(actor, object, state), - %Activity{} = activity <- Activity.get_by_id(activity.id) do - {:ok, activity} - else - e -> {:error, e} - end + "Follow" + |> Activity.Queries.by_type() + |> Activity.Queries.by_actor(actor) + |> Activity.Queries.by_object_id(object["id"]) + |> where(fragment("data->>'state' = 'pending'")) + |> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)]) + |> Repo.update_all([]) + + User.set_follow_state_cache(actor, object, state) + + activity = Activity.get_by_id(activity.id) + + {:ok, activity} end def update_follow_state( From e2011a667cdf5e67f257c9c30a02c206fb4df913 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 4 Sep 2019 18:35:01 +0000 Subject: [PATCH 038/272] Apply suggestion to lib/pleroma/web/activity_pub/utils.ex --- lib/pleroma/web/activity_pub/utils.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2de02f607..011acd48e 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -359,7 +359,7 @@ def update_follow_state_for_all( "Follow" |> Activity.Queries.by_type() |> Activity.Queries.by_actor(actor) - |> Activity.Queries.by_object_id(object["id"]) + |> Activity.Queries.by_object_id(object) |> where(fragment("data->>'state' = 'pending'")) |> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)]) |> Repo.update_all([]) From ae506ca997619f118d18703a9b0802246eb427d5 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 4 Sep 2019 21:40:53 +0300 Subject: [PATCH 039/272] fix formatting --- lib/pleroma/web/activity_pub/utils.ex | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 011acd48e..72e07b59d 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -356,19 +356,19 @@ def update_follow_state_for_all( %Activity{data: %{"actor" => actor, "object" => object}} = activity, state ) do - "Follow" - |> Activity.Queries.by_type() - |> Activity.Queries.by_actor(actor) - |> Activity.Queries.by_object_id(object) - |> where(fragment("data->>'state' = 'pending'")) - |> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)]) - |> Repo.update_all([]) - - User.set_follow_state_cache(actor, object, state) - - activity = Activity.get_by_id(activity.id) - - {:ok, activity} + "Follow" + |> Activity.Queries.by_type() + |> Activity.Queries.by_actor(actor) + |> Activity.Queries.by_object_id(object) + |> where(fragment("data->>'state' = 'pending'")) + |> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)]) + |> Repo.update_all([]) + + User.set_follow_state_cache(actor, object, state) + + activity = Activity.get_by_id(activity.id) + + {:ok, activity} end def update_follow_state( From 736165c082d34ef4d52367ea8315c228a1df3944 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 5 Sep 2019 16:54:34 +0300 Subject: [PATCH 040/272] Reverse reports list --- lib/pleroma/web/admin_api/views/report_view.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index 0b8745b2e..51b95ad5e 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -12,7 +12,8 @@ defmodule Pleroma.Web.AdminAPI.ReportView do def render("index.json", %{reports: reports}) do %{ - reports: render_many(reports[:items], __MODULE__, "show.json", as: :report), + reports: + render_many(reports[:items], __MODULE__, "show.json", as: :report) |> Enum.reverse(), total: reports[:total] } end From 40b3289c26137ee4d07c7fb79faf232714cc7592 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 6 Sep 2019 17:08:47 +0700 Subject: [PATCH 041/272] Refactor `add_link_headers/7` -> `add_link_headers/3` --- lib/pleroma/web/controller_helper.ex | 95 ++++++------------- .../controllers/mastodon_api_controller.ex | 28 +++--- .../web/pleroma_api/pleroma_api_controller.ex | 27 ++---- 3 files changed, 50 insertions(+), 100 deletions(-) diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index eeac9f503..b53a01955 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -34,79 +34,38 @@ defp param_to_integer(val, default) when is_binary(val) do defp param_to_integer(_, default), do: default - def add_link_headers( - conn, - method, - activities, - param \\ nil, - params \\ %{}, - func3 \\ nil, - func4 \\ nil - ) do - params = - conn.params - |> Map.drop(["since_id", "max_id", "min_id"]) - |> Map.merge(params) + def add_link_headers(conn, activities, extra_params \\ %{}) do + case List.last(activities) do + %{id: max_id} -> + params = + conn.params + |> Map.drop(Map.keys(conn.path_params)) + |> Map.drop(["since_id", "max_id", "min_id"]) + |> Map.merge(extra_params) - last = List.last(activities) + limit = + params + |> Map.get("limit", "20") + |> String.to_integer() - func3 = func3 || (&mastodon_api_url/3) - func4 = func4 || (&mastodon_api_url/4) + min_id = + if length(activities) <= limit do + activities + |> List.first() + |> Map.get(:id) + else + activities + |> Enum.at(limit * -1) + |> Map.get(:id) + end - if last do - max_id = last.id + next_url = current_url(conn, Map.merge(params, %{max_id: max_id})) + prev_url = current_url(conn, Map.merge(params, %{min_id: min_id})) - limit = - params - |> Map.get("limit", "20") - |> String.to_integer() + put_resp_header(conn, "link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"") - min_id = - if length(activities) <= limit do - activities - |> List.first() - |> Map.get(:id) - else - activities - |> Enum.at(limit * -1) - |> Map.get(:id) - end - - {next_url, prev_url} = - if param do - { - func4.( - Pleroma.Web.Endpoint, - method, - param, - Map.merge(params, %{max_id: max_id}) - ), - func4.( - Pleroma.Web.Endpoint, - method, - param, - Map.merge(params, %{min_id: min_id}) - ) - } - else - { - func3.( - Pleroma.Web.Endpoint, - method, - Map.merge(params, %{max_id: max_id}) - ), - func3.( - Pleroma.Web.Endpoint, - method, - Map.merge(params, %{min_id: min_id}) - ) - } - end - - conn - |> put_resp_header("link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"") - else - conn + _ -> + conn end end end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 8dfad7a54..f30a21bcc 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller import Pleroma.Web.ControllerHelper, - only: [json_response: 3, add_link_headers: 5, add_link_headers: 4, add_link_headers: 3] + only: [json_response: 3, add_link_headers: 2, add_link_headers: 3] alias Ecto.Changeset alias Pleroma.Activity @@ -365,7 +365,7 @@ def home_timeline(%{assigns: %{user: user}} = conn, params) do |> Enum.reverse() conn - |> add_link_headers(:home_timeline, activities) + |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) end @@ -384,7 +384,7 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do |> Enum.reverse() conn - |> add_link_headers(:public_timeline, activities, false, %{"local" => local_only}) + |> add_link_headers(activities, %{"local" => local_only}) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) end @@ -398,7 +398,7 @@ def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do activities = ActivityPub.fetch_user_activities(user, reading_user, params) conn - |> add_link_headers(:user_statuses, activities, params["id"]) + |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{ activities: activities, @@ -422,7 +422,7 @@ def dm_timeline(%{assigns: %{user: user}} = conn, params) do |> Pagination.fetch_paginated(params) conn - |> add_link_headers(:dm_timeline, activities) + |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) end @@ -523,7 +523,7 @@ def poll_vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choic def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do conn - |> add_link_headers(:scheduled_statuses, scheduled_activities) + |> add_link_headers(scheduled_activities) |> put_view(ScheduledActivityView) |> render("index.json", %{scheduled_activities: scheduled_activities}) end @@ -706,7 +706,7 @@ def notifications(%{assigns: %{user: user}} = conn, params) do notifications = MastodonAPI.get_notifications(user, params) conn - |> add_link_headers(:notifications, notifications) + |> add_link_headers(notifications) |> put_view(NotificationView) |> render("index.json", %{notifications: notifications, for: user}) end @@ -894,7 +894,7 @@ def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do |> Enum.reverse() conn - |> add_link_headers(:hashtag_timeline, activities, params["tag"], %{"local" => local_only}) + |> add_link_headers(activities, %{"local" => local_only}) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) end @@ -910,7 +910,7 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do end conn - |> add_link_headers(:followers, followers, user) + |> add_link_headers(followers) |> put_view(AccountView) |> render("accounts.json", %{for: for_user, users: followers, as: :user}) end @@ -927,7 +927,7 @@ def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do end conn - |> add_link_headers(:following, followers, user) + |> add_link_headers(followers) |> put_view(AccountView) |> render("accounts.json", %{for: for_user, users: followers, as: :user}) end @@ -1152,7 +1152,7 @@ def favourites(%{assigns: %{user: user}} = conn, params) do |> Enum.reverse() conn - |> add_link_headers(:favourites, activities) + |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) end @@ -1179,7 +1179,7 @@ def user_favourites(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params |> Enum.reverse() conn - |> add_link_headers(:favourites, activities) + |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: for_user, as: :activity}) else @@ -1200,7 +1200,7 @@ def bookmarks(%{assigns: %{user: user}} = conn, params) do |> Enum.map(fn b -> Map.put(b.activity, :bookmark, Map.delete(b, :activity)) end) conn - |> add_link_headers(:bookmarks, bookmarks) + |> add_link_headers(bookmarks) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) end @@ -1640,7 +1640,7 @@ def conversations(%{assigns: %{user: user}} = conn, params) do end) conn - |> add_link_headers(:conversations, participations) + |> add_link_headers(participations) |> json(conversations) end diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index f4df3b024..d17ccf84d 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do use Pleroma.Web, :controller - import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7] + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] alias Pleroma.Conversation.Participation alias Pleroma.Notification @@ -27,31 +27,22 @@ def conversation_statuses( %{assigns: %{user: user}} = conn, %{"id" => participation_id} = params ) do - params = - params - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> Map.put("user", user) - - participation = - participation_id - |> Participation.get(preload: [:conversation]) + participation = Participation.get(participation_id, preload: [:conversation]) if user.id == participation.user_id do + params = + params + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> Map.put("user", user) + activities = participation.conversation.ap_id |> ActivityPub.fetch_activities_for_context(params) |> Enum.reverse() conn - |> add_link_headers( - :conversation_statuses, - activities, - participation_id, - params, - nil, - &pleroma_api_url/4 - ) + |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) end From ab2f21e470f349f783f895f26da3041afcc3d73e Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 6 Sep 2019 21:50:00 +0300 Subject: [PATCH 042/272] tests for mastodon_api_controller.ex --- lib/pleroma/object.ex | 7 + lib/pleroma/user.ex | 22 +- .../controllers/mastodon_api_controller.ex | 143 +++---- lib/pleroma/web/oauth/app.ex | 26 ++ lib/pleroma/web/twitter_api/twitter_api.ex | 2 +- .../mastodon_api_controller_test.exs | 370 +++++++++++++++--- test/web/oauth/app_test.exs | 33 ++ 7 files changed, 438 insertions(+), 165 deletions(-) create mode 100644 test/web/oauth/app_test.exs diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index d58eb7f7d..4398b9739 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -228,4 +228,11 @@ def increase_vote_count(ap_id, name) do _ -> :noop end end + + @doc "Updates data field of an object" + def update_data(%Object{data: data} = object, attrs \\ %{}) do + object + |> Object.change(%{data: Map.merge(data || %{}, attrs)}) + |> Repo.update() + end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3aa245f2a..d9db985a6 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -499,6 +499,11 @@ def get_all_by_ap_id(ap_ids) do |> Repo.all() end + def get_all_by_ids(ids) do + from(u in __MODULE__, where: u.id in ^ids) + |> Repo.all() + end + # This is mostly an SPC migration fix. This guesses the user nickname by taking the last part # of the ap_id and the domain and tries to get that user def get_by_guessed_nickname(ap_id) do @@ -770,6 +775,19 @@ def update_note_count(%User{} = user) do |> update_and_set_cache() end + def update_mascot(user, url) do + info_changeset = + User.Info.mascot_update( + user.info, + url + ) + + user + |> change() + |> put_embed(:info, info_changeset) + |> update_and_set_cache() + end + @spec maybe_fetch_follow_information(User.t()) :: User.t() def maybe_fetch_follow_information(user) do with {:ok, user} <- fetch_follow_information(user) do @@ -917,9 +935,7 @@ def subscribe(subscriber, %{ap_id: ap_id}) do def unsubscribe(unsubscriber, %{ap_id: ap_id}) do with %User{} = user <- get_cached_by_ap_id(ap_id) do - info_cng = - user.info - |> User.Info.remove_from_subscribers(unsubscriber.ap_id) + info_cng = User.Info.remove_from_subscribers(user.info, unsubscriber.ap_id) change(user) |> put_embed(:info, info_cng) diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 8dfad7a54..e4e0a7ac9 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -447,8 +447,7 @@ def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do result = %{ ancestors: - StatusView.render( - "index.json", + StatusView.render("index.json", for: user, activities: grouped_activities[true] || [], as: :activity @@ -456,8 +455,7 @@ def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do |> Enum.reverse(), # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart descendants: - StatusView.render( - "index.json", + StatusView.render("index.json", for: user, activities: grouped_activities[false] || [], as: :activity @@ -746,9 +744,7 @@ def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params end def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do - id = List.wrap(id) - q = from(u in User, where: u.id in ^id) - targets = Repo.all(q) + targets = User.get_all_by_ids(List.wrap(id)) conn |> put_view(AccountView) @@ -758,19 +754,15 @@ def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do # Instead of returning a 400 when no "id" params is present, Mastodon returns an empty array. def relationships(%{assigns: %{user: _user}} = conn, _), do: json(conn, []) - def update_media(%{assigns: %{user: user}} = conn, data) do - with %Object{} = object <- Repo.get(Object, data["id"]), + def update_media( + %{assigns: %{user: user}} = conn, + %{"id" => id, "description" => description} = _ + ) + when is_binary(description) do + with %Object{} = object <- Repo.get(Object, id), true <- Object.authorize_mutation(object, user), - true <- is_binary(data["description"]), - description <- data["description"] do - new_data = %{object.data | "name" => description} - - {:ok, _} = - object - |> Object.change(%{data: new_data}) - |> Repo.update() - - attachment_data = Map.put(new_data, "id", object.id) + {:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do + attachment_data = Map.put(data, "id", object.id) conn |> put_view(StatusView) @@ -778,6 +770,8 @@ def update_media(%{assigns: %{user: user}} = conn, data) do end end + def update_media(_conn, _data), do: {:error, :bad_request} + def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do with {:ok, object} <- ActivityPub.upload( @@ -796,34 +790,23 @@ def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do def set_mascot(%{assigns: %{user: user}} = conn, %{"file" => file}) do with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), %{} = attachment_data <- Map.put(object.data, "id", object.id), - %{type: type} = rendered <- - StatusView.render("attachment.json", %{attachment: attachment_data}) do - # Reject if not an image - if type == "image" do - # Sure! - # Save to the user's info - info_changeset = User.Info.mascot_update(user.info, rendered) - - user_changeset = - user - |> Changeset.change() - |> Changeset.put_embed(:info, info_changeset) - - {:ok, _user} = User.update_and_set_cache(user_changeset) - - conn - |> json(rendered) - else + %{type: "image"} = rendered <- + StatusView.render("attachment.json", %{attachment: attachment_data}), + {:ok, _user} = User.update_mascot(user, rendered) do + json(conn, rendered) + else + %{type: _type} = _ -> render_error(conn, :unsupported_media_type, "mascots can only be images") - end + + e -> + e end end def get_mascot(%{assigns: %{user: user}} = conn, _params) do mascot = User.get_mascot(user) - conn - |> json(mascot) + json(conn, mascot) end def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do @@ -1119,10 +1102,8 @@ def subscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do |> put_view(AccountView) |> render("relationship.json", %{user: user, target: subscription_target}) else - {:error, message} -> - conn - |> put_status(:forbidden) - |> json(%{error: message}) + nil -> {:error, :not_found} + e -> e end end @@ -1133,10 +1114,8 @@ def unsubscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do |> put_view(AccountView) |> render("relationship.json", %{user: user, target: subscription_target}) else - {:error, message} -> - conn - |> put_status(:forbidden) - |> json(%{error: message}) + nil -> {:error, :not_found} + e -> e end end @@ -1207,8 +1186,10 @@ def bookmarks(%{assigns: %{user: user}} = conn, params) do def account_lists(%{assigns: %{user: user}} = conn, %{"id" => account_id}) do lists = Pleroma.List.get_lists_account_belongs(user, account_id) - res = ListView.render("lists.json", lists: lists) - json(conn, res) + + conn + |> put_view(ListView) + |> render("index.json", %{lists: lists}) end def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do @@ -1363,7 +1344,7 @@ def login(%{assigns: %{user: %User{}}} = conn, _params) do @doc "Local Mastodon FE login init action" def login(conn, %{"code" => auth_token}) do with {:ok, app} <- get_or_make_app(), - %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id), + {:ok, auth} <- Authorization.get_by_token(app, auth_token), {:ok, token} <- Token.exchange_token(app, auth) do conn |> put_session(:oauth_token, token.token) @@ -1375,9 +1356,7 @@ def login(conn, %{"code" => auth_token}) do def login(conn, _) do with {:ok, app} <- get_or_make_app() do path = - o_auth_path( - conn, - :authorize, + o_auth_path(conn, :authorize, response_type: "code", client_id: app.client_id, redirect_uri: ".", @@ -1399,31 +1378,12 @@ defp local_mastodon_root_path(conn) do end end + @spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()} defp get_or_make_app do - find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."} - scopes = ["read", "write", "follow", "push"] - - with %App{} = app <- Repo.get_by(App, find_attrs) do - {:ok, app} = - if app.scopes == scopes do - {:ok, app} - else - app - |> Changeset.change(%{scopes: scopes}) - |> Repo.update() - end - - {:ok, app} - else - _e -> - cs = - App.register_changeset( - %App{}, - Map.put(find_attrs, :scopes, scopes) - ) - - Repo.insert(cs) - end + App.get_or_make( + %{client_name: @local_mastodon_name, redirect_uris: "."}, + ["read", "write", "follow", "push"] + ) end def logout(conn, _) do @@ -1432,26 +1392,13 @@ def logout(conn, _) do |> redirect(to: "/") end - def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do - Logger.debug("Unimplemented, returning unmodified relationship") - - with %User{} = target <- User.get_cached_by_id(id) do - conn - |> put_view(AccountView) - |> render("relationship.json", %{user: user, target: target}) - end - end - + # Stubs for unimplemented mastodon api + # def empty_array(conn, _) do Logger.debug("Unimplemented, returning an empty array") json(conn, []) end - def empty_object(conn, _) do - Logger.debug("Unimplemented, returning an empty object") - json(conn, %{}) - end - def get_filters(%{assigns: %{user: user}} = conn, _) do filters = Filter.get_filters(user) res = FilterView.render("filters.json", filters: filters) @@ -1570,7 +1517,7 @@ def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do json(conn, data) else _e -> - %{} + json(conn, %{}) end end @@ -1623,7 +1570,7 @@ def account_register( end end - def account_register(%{assigns: %{app: _app}} = conn, _params) do + def account_register(%{assigns: %{app: _app}} = conn, _) do render_error(conn, :bad_request, "Missing parameters") end @@ -1682,15 +1629,15 @@ def account_confirmation_resend(conn, params) do end end - def try_render(conn, target, params) - when is_binary(target) do + defp try_render(conn, target, params) + when is_binary(target) do case render(conn, target, params) do nil -> render_error(conn, :not_implemented, "Can't display this activity") res -> res end end - def try_render(conn, _, _) do + defp try_render(conn, _, _) do render_error(conn, :not_implemented, "Can't display this activity") end diff --git a/lib/pleroma/web/oauth/app.ex b/lib/pleroma/web/oauth/app.ex index ddcdb1871..cc3fb1ce5 100644 --- a/lib/pleroma/web/oauth/app.ex +++ b/lib/pleroma/web/oauth/app.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.OAuth.App do use Ecto.Schema import Ecto.Changeset + alias Pleroma.Repo @type t :: %__MODULE__{} @@ -39,4 +40,29 @@ def register_changeset(struct, params \\ %{}) do changeset end end + + @doc """ + Gets app by attrs or create new with attrs. + And updates the scopes if need. + """ + @spec get_or_make(map(), list(String.t())) :: {:ok, App.t()} | {:error, Ecto.Changeset.t()} + def get_or_make(attrs, scopes) do + with %__MODULE__{} = app <- Repo.get_by(__MODULE__, attrs) do + update_scopes(app, scopes) + else + _e -> + %__MODULE__{} + |> register_changeset(Map.put(attrs, :scopes, scopes)) + |> Repo.insert() + end + end + + defp update_scopes(%__MODULE__{} = app, []), do: {:ok, app} + defp update_scopes(%__MODULE__{scopes: scopes} = app, scopes), do: {:ok, app} + + defp update_scopes(%__MODULE__{} = app, scopes) do + app + |> change(%{scopes: scopes}) + |> Repo.update() + end end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 8eda762c7..bfd838902 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -29,7 +29,7 @@ def register_user(params, opts \\ []) do captcha_enabled = Pleroma.Config.get([Pleroma.Captcha, :enabled]) # true if captcha is disabled or enabled and valid, false otherwise captcha_ok = - if !captcha_enabled do + if not captcha_enabled do :ok else Pleroma.Captcha.validate( diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index e18f8f0d1..a331d6455 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1551,6 +1551,17 @@ test "returns the relationships for the current user", %{conn: conn} do assert to_string(other_user.id) == relationship["id"] end + + test "returns an empty list when bad request", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/accounts/relationships", %{}) + + assert [] = json_response(conn, 200) + end end describe "media upload" do @@ -1752,70 +1763,72 @@ test "respects limit_to_local_content == :unauthenticated for remote user nickna end end - test "mascot upload", %{conn: conn} do - user = insert(:user) + describe "/api/v1/pleroma/mascot" do + test "mascot upload", %{conn: conn} do + user = insert(:user) - non_image_file = %Plug.Upload{ - content_type: "audio/mpeg", - path: Path.absname("test/fixtures/sound.mp3"), - filename: "sound.mp3" - } + non_image_file = %Plug.Upload{ + content_type: "audio/mpeg", + path: Path.absname("test/fixtures/sound.mp3"), + filename: "sound.mp3" + } - conn = - conn - |> assign(:user, user) - |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) + conn = + conn + |> assign(:user, user) + |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) - assert json_response(conn, 415) + assert json_response(conn, 415) - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } - conn = - build_conn() - |> assign(:user, user) - |> put("/api/v1/pleroma/mascot", %{"file" => file}) + conn = + build_conn() + |> assign(:user, user) + |> put("/api/v1/pleroma/mascot", %{"file" => file}) - assert %{"id" => _, "type" => image} = json_response(conn, 200) - end + assert %{"id" => _, "type" => image} = json_response(conn, 200) + end - test "mascot retrieving", %{conn: conn} do - user = insert(:user) - # When user hasn't set a mascot, we should just get pleroma tan back - conn = - conn - |> assign(:user, user) - |> get("/api/v1/pleroma/mascot") + test "mascot retrieving", %{conn: conn} do + user = insert(:user) + # When user hasn't set a mascot, we should just get pleroma tan back + conn = + conn + |> assign(:user, user) + |> get("/api/v1/pleroma/mascot") - assert %{"url" => url} = json_response(conn, 200) - assert url =~ "pleroma-fox-tan-smol" + assert %{"url" => url} = json_response(conn, 200) + assert url =~ "pleroma-fox-tan-smol" - # When a user sets their mascot, we should get that back - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } + # When a user sets their mascot, we should get that back + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } - conn = - build_conn() - |> assign(:user, user) - |> put("/api/v1/pleroma/mascot", %{"file" => file}) + conn = + build_conn() + |> assign(:user, user) + |> put("/api/v1/pleroma/mascot", %{"file" => file}) - assert json_response(conn, 200) + assert json_response(conn, 200) - user = User.get_cached_by_id(user.id) + user = User.get_cached_by_id(user.id) - conn = - build_conn() - |> assign(:user, user) - |> get("/api/v1/pleroma/mascot") + conn = + build_conn() + |> assign(:user, user) + |> get("/api/v1/pleroma/mascot") - assert %{"url" => url, "type" => "image"} = json_response(conn, 200) - assert url =~ "an_image" + assert %{"url" => url, "type" => "image"} = json_response(conn, 200) + assert url =~ "an_image" + end end test "hashtag timeline", %{conn: conn} do @@ -2183,23 +2196,51 @@ test "without notifications", %{conn: conn} do end end - test "subscribing / unsubscribing to a user", %{conn: conn} do - user = insert(:user) - subscription_target = insert(:user) + describe "subscribing / unsubscribing" do + test "subscribing / unsubscribing to a user", %{conn: conn} do + user = insert(:user) + subscription_target = insert(:user) - conn = - conn - |> assign(:user, user) - |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") + conn = + conn + |> assign(:user, user) + |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") - assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200) + assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200) - conn = - build_conn() - |> assign(:user, user) - |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") + conn = + build_conn() + |> assign(:user, user) + |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") - assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200) + assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200) + end + end + + describe "subscribing" do + test "returns 404 when subscription_target not found", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/pleroma/accounts/target_id/subscribe") + + assert %{"error" => "Record not found"} = json_response(conn, 404) + end + end + + describe "unsubscribing" do + test "returns 404 when subscription_target not found", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/pleroma/accounts/target_id/unsubscribe") + + assert %{"error" => "Record not found"} = json_response(conn, 404) + end end test "getting a list of mutes", %{conn: conn} do @@ -2814,6 +2855,15 @@ test "replaces missing description with an empty string", %{conn: conn, user: us } } end + + test "returns empty object when id invalid", %{conn: conn} do + response = + conn + |> get("/api/v1/statuses/9eoozpwTul5mjSEDRI/card") + |> json_response(200) + + assert response == %{} + end end test "bookmarks" do @@ -3133,6 +3183,18 @@ test "redirects to the saved path after log in", %{conn: conn, path: path} do assert conn.status == 302 assert redirected_to(conn) == path end + end + + describe "GET /web/login" do + test "redirects to /oauth/authorize", %{conn: conn} do + app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") + conn = get(conn, "/web/login", %{}) + + assert conn.status == 302 + + assert redirected_to(conn) == + "/oauth/authorize?response_type=code&client_id=#{app.client_id}&redirect_uri=.&scope=read+write+follow+push" + end test "redirects to the getting-started page when referer is not present", %{conn: conn} do app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") @@ -3143,6 +3205,18 @@ test "redirects to the getting-started page when referer is not present", %{conn assert conn.status == 302 assert redirected_to(conn) == "/web/getting-started" end + + test "redirects to the getting-started page when user assigned", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> get("/web/login", %{}) + + assert conn.status == 302 + assert redirected_to(conn) == "/web/getting-started" + end end describe "scheduled activities" do @@ -3401,6 +3475,17 @@ test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{c end describe "create account by app" do + setup do + valid_params = %{ + username: "lain", + email: "lain@example.org", + password: "PlzDontHackLain", + agreement: true + } + + [valid_params: valid_params] + end + test "Account registration via Application", %{conn: conn} do conn = conn @@ -3444,6 +3529,7 @@ test "Account registration via Application", %{conn: conn} do username: "lain", email: "lain@example.org", password: "PlzDontHackLain", + bio: "Test Bio", agreement: true }) @@ -3462,6 +3548,18 @@ test "Account registration via Application", %{conn: conn} do assert token_from_db.user.info.confirmation_pending end + test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do + _user = insert(:user, email: "lain@example.org") + app_token = insert(:oauth_token, user: nil) + + conn = + conn + |> put_req_header("authorization", "Bearer " <> app_token.token) + + res = post(conn, "/api/v1/accounts", valid_params) + assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"} + end + test "rate limit", %{conn: conn} do app_token = insert(:oauth_token, user: nil) @@ -3505,6 +3603,41 @@ test "rate limit", %{conn: conn} do assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"} end + + test "returns bad_request if missing required params", %{ + conn: conn, + valid_params: valid_params + } do + app_token = insert(:oauth_token, user: nil) + + conn = + conn + |> put_req_header("authorization", "Bearer " <> app_token.token) + + res = post(conn, "/api/v1/accounts", valid_params) + assert json_response(res, 200) + + Enum.each(valid_params, fn {attr, _} -> + res = + conn + |> Map.put( + :remote_ip, + {:rand.uniform(15), :rand.uniform(15), :rand.uniform(15), :rand.uniform(15)} + ) + |> post("/api/v1/accounts", Map.delete(valid_params, attr)) + + assert json_response(res, 400) == %{"error" => "Missing parameters"} + end) + end + + test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do + conn = + conn + |> put_req_header("authorization", "Bearer " <> "invalid-token") + + res = post(conn, "/api/v1/accounts", valid_params) + assert json_response(res, 403) == %{"error" => "Invalid credentials"} + end end describe "GET /api/v1/polls/:id" do @@ -3988,4 +4121,115 @@ test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do ] end end + + describe "PUT /api/v1/media/:id" do + setup do + actor = insert(:user) + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + {:ok, %Object{} = object} = + ActivityPub.upload( + file, + actor: User.ap_id(actor), + description: "test-m" + ) + + [actor: actor, object: object] + end + + test "updates name of media", %{conn: conn, actor: actor, object: object} do + media = + conn + |> assign(:user, actor) + |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"}) + |> json_response(:ok) + + assert media["description"] == "test-media" + assert refresh_record(object).data["name"] == "test-media" + end + + test "returns error wheb request is bad", %{conn: conn, actor: actor, object: object} do + media = + conn + |> assign(:user, actor) + |> put("/api/v1/media/#{object.id}", %{}) + |> json_response(400) + + assert media == %{"error" => "bad_request"} + end + end + + describe "DELETE /auth/sign_out" do + test "redirect to root page", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> delete("/auth/sign_out") + + assert conn.status == 302 + assert redirected_to(conn) == "/" + end + end + + describe "GET /api/v1/accounts/:id/lists - account_lists" do + test "returns lists to which the account belongs", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user) + {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user) + + res = + conn + |> assign(:user, user) + |> get("/api/v1/accounts/#{other_user.id}/lists") + |> json_response(200) + + assert res == [%{"id" => to_string(list.id), "title" => "Test List"}] + end + end + + describe "empty_array, stubs for mastodon api" do + test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do + user = insert(:user) + + res = + conn + |> assign(:user, user) + |> get("/api/v1/accounts/#{user.id}/identity_proofs") + |> json_response(200) + + assert res == [] + end + + test "GET /api/v1/endorsements", %{conn: conn} do + user = insert(:user) + + res = + conn + |> assign(:user, user) + |> get("/api/v1/endorsements") + |> json_response(200) + + assert res == [] + end + + test "GET /api/v1/trends", %{conn: conn} do + user = insert(:user) + + res = + conn + |> assign(:user, user) + |> get("/api/v1/trends") + |> json_response(200) + + assert res == [] + end + end end diff --git a/test/web/oauth/app_test.exs b/test/web/oauth/app_test.exs new file mode 100644 index 000000000..195b8c17f --- /dev/null +++ b/test/web/oauth/app_test.exs @@ -0,0 +1,33 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.AppTest do + use Pleroma.DataCase + + alias Pleroma.Web.OAuth.App + import Pleroma.Factory + + describe "get_or_make/2" do + test "gets exist app" do + attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} + app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]})) + {:ok, %App{} = exist_app} = App.get_or_make(attrs, []) + assert exist_app == app + end + + test "make app" do + attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} + {:ok, %App{} = app} = App.get_or_make(attrs, ["write"]) + assert app.scopes == ["write"] + end + + test "gets exist app and updates scopes" do + attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} + app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]})) + {:ok, %App{} = exist_app} = App.get_or_make(attrs, ["read", "write", "follow", "push"]) + assert exist_app.id == app.id + assert exist_app.scopes == ["read", "write", "follow", "push"] + end + end +end From a31af93e1d10d9db8796d86ccda35873697b5a4c Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 10 Sep 2019 16:43:10 +0300 Subject: [PATCH 043/272] added tests /activity_pub/transmogrifier.ex --- .../web/activity_pub/transmogrifier.ex | 264 +++++++----------- test/web/activity_pub/transmogrifier_test.exs | 162 +++++++++++ 2 files changed, 270 insertions(+), 156 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 468961bd0..93b3a1f97 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -41,8 +41,7 @@ def fix_object(object, options \\ []) do end def fix_summary(%{"summary" => nil} = object) do - object - |> Map.put("summary", "") + Map.put(object, "summary", "") end def fix_summary(%{"summary" => _} = object) do @@ -50,10 +49,7 @@ def fix_summary(%{"summary" => _} = object) do object end - def fix_summary(object) do - object - |> Map.put("summary", "") - end + def fix_summary(object), do: Map.put(object, "summary", "") def fix_addressing_list(map, field) do cond do @@ -73,13 +69,9 @@ def fix_explicit_addressing( explicit_mentions, follower_collection ) do - explicit_to = - to - |> Enum.filter(fn x -> x in explicit_mentions end) + explicit_to = Enum.filter(to, fn x -> x in explicit_mentions end) - explicit_cc = - to - |> Enum.filter(fn x -> x not in explicit_mentions end) + explicit_cc = Enum.filter(to, fn x -> x not in explicit_mentions end) final_cc = (cc ++ explicit_cc) @@ -97,13 +89,19 @@ def fix_explicit_addressing(object, _explicit_mentions, _followers_collection), def fix_explicit_addressing(%{"directMessage" => true} = object), do: object def fix_explicit_addressing(object) do - explicit_mentions = + explicit_mentions = Utils.determine_explicit_mentions(object) + + %User{follower_address: follower_collection} = object - |> Utils.determine_explicit_mentions() + |> Containment.get_actor() + |> User.get_cached_by_ap_id() - follower_collection = User.get_cached_by_ap_id(Containment.get_actor(object)).follower_address - - explicit_mentions = explicit_mentions ++ [Pleroma.Constants.as_public(), follower_collection] + explicit_mentions = + explicit_mentions ++ + [ + Pleroma.Constants.as_public(), + follower_collection + ] fix_explicit_addressing(object, explicit_mentions, follower_collection) end @@ -147,48 +145,25 @@ def fix_addressing(object) do end def fix_actor(%{"attributedTo" => actor} = object) do - object - |> Map.put("actor", Containment.get_actor(%{"actor" => actor})) + Map.put(object, "actor", Containment.get_actor(%{"actor" => actor})) end def fix_in_reply_to(object, options \\ []) def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options) when not is_nil(in_reply_to) do - in_reply_to_id = - cond do - is_bitstring(in_reply_to) -> - in_reply_to - - is_map(in_reply_to) && is_bitstring(in_reply_to["id"]) -> - in_reply_to["id"] - - is_list(in_reply_to) && is_bitstring(Enum.at(in_reply_to, 0)) -> - Enum.at(in_reply_to, 0) - - # Maybe I should output an error too? - true -> - "" - end - + in_reply_to_id = prepare_in_reply_to(in_reply_to) object = Map.put(object, "inReplyToAtomUri", in_reply_to_id) if Federator.allowed_incoming_reply_depth?(options[:depth]) do - case get_obj_helper(in_reply_to_id, options) do - {:ok, replied_object} -> - with %Activity{} = _activity <- - Activity.get_create_by_object_ap_id(replied_object.data["id"]) do - object - |> Map.put("inReplyTo", replied_object.data["id"]) - |> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id) - |> Map.put("conversation", replied_object.data["context"] || object["conversation"]) - |> Map.put("context", replied_object.data["context"] || object["conversation"]) - else - e -> - Logger.error("Couldn't fetch \"#{inspect(in_reply_to_id)}\", error: #{inspect(e)}") - object - end - + with {:ok, replied_object} <- get_obj_helper(in_reply_to_id, options), + %Activity{} = _ <- Activity.get_create_by_object_ap_id(replied_object.data["id"]) do + object + |> Map.put("inReplyTo", replied_object.data["id"]) + |> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id) + |> Map.put("conversation", replied_object.data["context"] || object["conversation"]) + |> Map.put("context", replied_object.data["context"] || object["conversation"]) + else e -> Logger.error("Couldn't fetch \"#{inspect(in_reply_to_id)}\", error: #{inspect(e)}") object @@ -200,6 +175,22 @@ def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options) def fix_in_reply_to(object, _options), do: object + defp prepare_in_reply_to(in_reply_to) do + cond do + is_bitstring(in_reply_to) -> + in_reply_to + + is_map(in_reply_to) && is_bitstring(in_reply_to["id"]) -> + in_reply_to["id"] + + is_list(in_reply_to) && is_bitstring(Enum.at(in_reply_to, 0)) -> + Enum.at(in_reply_to, 0) + + true -> + "" + end + end + def fix_context(object) do context = object["context"] || object["conversation"] || Utils.generate_context_id() @@ -210,8 +201,7 @@ def fix_context(object) do def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do attachments = - attachment - |> Enum.map(fn data -> + Enum.map(attachment, fn data -> media_type = data["mediaType"] || data["mimeType"] href = data["url"] || data["href"] @@ -222,30 +212,23 @@ def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachm |> Map.put("url", url) end) - object - |> Map.put("attachment", attachments) + Map.put(object, "attachment", attachments) end def fix_attachments(%{"attachment" => attachment} = object) when is_map(attachment) do - Map.put(object, "attachment", [attachment]) - |> fix_attachments() + fix_attachments(Map.put(object, "attachment", [attachment])) end def fix_attachments(object), do: object def fix_url(%{"url" => url} = object) when is_map(url) do - object - |> Map.put("url", url["href"]) + Map.put(object, "url", url["href"]) end def fix_url(%{"type" => "Video", "url" => url} = object) when is_list(url) do first_element = Enum.at(url, 0) - link_element = - url - |> Enum.filter(fn x -> is_map(x) end) - |> Enum.filter(fn x -> x["mimeType"] == "text/html" end) - |> Enum.at(0) + link_element = Enum.find(url, fn x -> is_map(x) and x["mimeType"] == "text/html" end) object |> Map.put("attachment", [first_element]) @@ -263,36 +246,32 @@ def fix_url(%{"type" => object_type, "url" => url} = object) true -> "" end - object - |> Map.put("url", url_string) + Map.put(object, "url", url_string) end def fix_url(object), do: object def fix_emoji(%{"tag" => tags} = object) when is_list(tags) do - emoji = tags |> Enum.filter(fn data -> data["type"] == "Emoji" and data["icon"] end) - emoji = - emoji + tags + |> Enum.filter(fn data -> data["type"] == "Emoji" and data["icon"] end) |> Enum.reduce(%{}, fn data, mapping -> name = String.trim(data["name"], ":") - mapping |> Map.put(name, data["icon"]["url"]) + Map.put(mapping, name, data["icon"]["url"]) end) # we merge mastodon and pleroma emoji into a single mapping, to allow for both wire formats emoji = Map.merge(object["emoji"] || %{}, emoji) - object - |> Map.put("emoji", emoji) + Map.put(object, "emoji", emoji) end def fix_emoji(%{"tag" => %{"type" => "Emoji"} = tag} = object) do name = String.trim(tag["name"], ":") emoji = %{name => tag["icon"]["url"]} - object - |> Map.put("emoji", emoji) + Map.put(object, "emoji", emoji) end def fix_emoji(object), do: object @@ -303,17 +282,13 @@ def fix_tag(%{"tag" => tag} = object) when is_list(tag) do |> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end) |> Enum.map(fn data -> String.slice(data["name"], 1..-1) end) - combined = tag ++ tags - - object - |> Map.put("tag", combined) + Map.put(object, "tag", tag ++ tags) end def fix_tag(%{"tag" => %{"type" => "Hashtag", "name" => hashtag} = tag} = object) do combined = [tag, String.slice(hashtag, 1..-1)] - object - |> Map.put("tag", combined) + Map.put(object, "tag", combined) end def fix_tag(%{"tag" => %{} = tag} = object), do: Map.put(object, "tag", [tag]) @@ -325,8 +300,7 @@ def fix_content_map(%{"contentMap" => content_map} = object) do content_groups = Map.to_list(content_map) {_, content} = Enum.at(content_groups, 0) - object - |> Map.put("content", content) + Map.put(object, "content", content) end def fix_content_map(object), do: object @@ -335,16 +309,11 @@ def fix_type(object, options \\ []) def fix_type(%{"inReplyTo" => reply_id, "name" => _} = object, options) when is_binary(reply_id) do - reply = - with true <- Federator.allowed_incoming_reply_depth?(options[:depth]), - {:ok, object} <- get_obj_helper(reply_id, options) do - object - end - - if reply && reply.data["type"] == "Question" do + with true <- Federator.allowed_incoming_reply_depth?(options[:depth]), + {:ok, %{data: %{"type" => "Question"} = _} = _} <- get_obj_helper(reply_id, options) do Map.put(object, "type", "Answer") else - object + _ -> object end end @@ -376,6 +345,17 @@ defp get_follow_activity(follow_object, followed) do end end + # Reduce the object list to find the reported user. + defp get_reported(objects) do + Enum.reduce_while(objects, nil, fn ap_id, _ -> + with %User{} = user <- User.get_cached_by_ap_id(ap_id) do + {:halt, user} + else + _ -> {:cont, nil} + end + end) + end + def handle_incoming(data, options \\ []) # Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them @@ -384,31 +364,19 @@ def handle_incoming(%{"type" => "Flag", "object" => objects, "actor" => actor} = with context <- data["context"] || Utils.generate_context_id(), content <- data["content"] || "", %User{} = actor <- User.get_cached_by_ap_id(actor), - # Reduce the object list to find the reported user. - %User{} = account <- - Enum.reduce_while(objects, nil, fn ap_id, _ -> - with %User{} = user <- User.get_cached_by_ap_id(ap_id) do - {:halt, user} - else - _ -> {:cont, nil} - end - end), - + %User{} = account <- get_reported(objects), # Remove the reported user from the object list. statuses <- Enum.filter(objects, fn ap_id -> ap_id != account.ap_id end) do - params = %{ + %{ actor: actor, context: context, account: account, statuses: statuses, content: content, - additional: %{ - "cc" => [account.ap_id] - } + additional: %{"cc" => [account.ap_id]} } - - ActivityPub.flag(params) + |> ActivityPub.flag() end end @@ -755,8 +723,13 @@ def handle_incoming( def handle_incoming(_, _), do: :error + @spec get_obj_helper(String.t(), Keyword.t()) :: {:ok, Object.t()} | nil def get_obj_helper(id, options \\ []) do - if object = Object.normalize(id, true, options), do: {:ok, object}, else: nil + if object = Object.normalize(id, true, options) do + {:ok, object} + else + nil + end end def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) when is_binary(in_reply_to) do @@ -855,27 +828,24 @@ def prepare_outgoing(%{"type" => _type} = data) do {:ok, data} end - def maybe_fix_object_url(data) do - if is_binary(data["object"]) and not String.starts_with?(data["object"], "http") do - case get_obj_helper(data["object"]) do - {:ok, relative_object} -> - if relative_object.data["external_url"] do - _data = - data - |> Map.put("object", relative_object.data["external_url"]) - else - data - end - - e -> - Logger.error("Couldn't fetch #{data["object"]} #{inspect(e)}") - data - end + def maybe_fix_object_url(%{"object" => object} = data) when is_binary(object) do + with false <- String.starts_with?(object, "http"), + {:fetch, {:ok, relative_object}} <- {:fetch, get_obj_helper(object)}, + %{data: %{"external_url" => external_url}} when not is_nil(external_url) <- + relative_object do + Map.put(data, "object", external_url) else - data + {:fetch, e} -> + Logger.error("Couldn't fetch #{object} #{inspect(e)}") + data + + _ -> + data end end + def maybe_fix_object_url(data), do: data + def add_hashtags(object) do tags = (object["tag"] || []) @@ -893,8 +863,7 @@ def add_hashtags(object) do tag end) - object - |> Map.put("tag", tags) + Map.put(object, "tag", tags) end def add_mention_tags(object) do @@ -907,15 +876,13 @@ def add_mention_tags(object) do tags = object["tag"] || [] - object - |> Map.put("tag", tags ++ mentions) + Map.put(object, "tag", tags ++ mentions) end def add_emoji_tags(%User{info: %{"emoji" => _emoji} = user_info} = object) do user_info = add_emoji_tags(user_info) - object - |> Map.put(:info, user_info) + Map.put(object, :info, user_info) end # TODO: we should probably send mtime instead of unix epoch time for updated @@ -923,8 +890,7 @@ def add_emoji_tags(%{"emoji" => emoji} = object) do tags = object["tag"] || [] out = - emoji - |> Enum.map(fn {name, url} -> + Enum.map(emoji, fn {name, url} -> %{ "icon" => %{"url" => url, "type" => "Image"}, "name" => ":" <> name <> ":", @@ -934,13 +900,10 @@ def add_emoji_tags(%{"emoji" => emoji} = object) do } end) - object - |> Map.put("tag", tags ++ out) + Map.put(object, "tag", tags ++ out) end - def add_emoji_tags(object) do - object - end + def add_emoji_tags(object), do: object def set_conversation(object) do Map.put(object, "conversation", object["context"]) @@ -959,9 +922,7 @@ def set_type(object), do: object def add_attributed_to(object) do attributed_to = object["attributedTo"] || object["actor"] - - object - |> Map.put("attributedTo", attributed_to) + Map.put(object, "attributedTo", attributed_to) end def prepare_attachments(object) do @@ -972,8 +933,7 @@ def prepare_attachments(object) do %{"url" => href, "mediaType" => media_type, "name" => data["name"], "type" => "Document"} end) - object - |> Map.put("attachment", attachments) + Map.put(object, "attachment", attachments) end defp strip_internal_fields(object) do @@ -990,12 +950,9 @@ defp strip_internal_fields(object) do end defp strip_internal_tags(%{"tag" => tags} = object) do - tags = - tags - |> Enum.filter(fn x -> is_map(x) end) + tags = Enum.filter(tags, fn x -> is_map(x) end) - object - |> Map.put("tag", tags) + Map.put(object, "tag", tags) end defp strip_internal_tags(object), do: object @@ -1074,16 +1031,11 @@ def maybe_retire_websub(ap_id) do end end - def maybe_fix_user_url(data) do - if is_map(data["url"]) do - Map.put(data, "url", data["url"]["href"]) - else - data - end + def maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do + Map.put(data, "url", url["href"]) end - def maybe_fix_user_object(data) do - data - |> maybe_fix_user_url - end + def maybe_fix_user_url(data), do: data + + def maybe_fix_user_object(data), do: maybe_fix_user_url(data) end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 0661d5d7c..63c869d35 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1451,4 +1451,166 @@ test "removes recipient's follower collection from cc", %{user: user} do refute recipient.follower_address in fixed_object["to"] end end + + describe "fix_summary/1" do + test "returns fixed object" do + assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""} + assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"} + assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""} + end + end + + describe "fix_in_reply_to/2" do + clear_config([:instance, :federation_incoming_replies_max_depth]) + + setup do + data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) + [data: data] + end + + test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do + assert Transmogrifier.fix_in_reply_to(data) == data + end + + test "returns object with inReplyToAtomUri when denied incoming reply", %{data: data} do + Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) + + object_with_reply = + Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873") + + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873" + assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + + object_with_reply = + Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"}) + + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"} + assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + + object_with_reply = + Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"]) + + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"] + assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + + object_with_reply = Map.put(data["object"], "inReplyTo", []) + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == [] + assert modified_object["inReplyToAtomUri"] == "" + end + + test "returns modified object when allowed incoming reply", %{data: data} do + object_with_reply = + Map.put( + data["object"], + "inReplyTo", + "https://shitposter.club/notice/2827873" + ) + + Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5) + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + + assert modified_object["inReplyTo"] == + "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" + + assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + + assert modified_object["conversation"] == + "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26" + + assert modified_object["context"] == + "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26" + end + end + + describe "fix_url/1" do + test "fixes data for object when url is map" do + object = %{ + "url" => %{ + "type" => "Link", + "mimeType" => "video/mp4", + "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" + } + } + + assert Transmogrifier.fix_url(object) == %{ + "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" + } + end + + test "fixes data for video object" do + object = %{ + "type" => "Video", + "url" => [ + %{ + "type" => "Link", + "mimeType" => "video/mp4", + "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" + }, + %{ + "type" => "Link", + "mimeType" => "video/mp4", + "href" => "https://peertube46fb-ad81-2d4c2d1630e3-240.mp4" + }, + %{ + "type" => "Link", + "mimeType" => "text/html", + "href" => "https://peertube.-2d4c2d1630e3" + }, + %{ + "type" => "Link", + "mimeType" => "text/html", + "href" => "https://peertube.-2d4c2d16377-42" + } + ] + } + + assert Transmogrifier.fix_url(object) == %{ + "attachment" => [ + %{ + "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4", + "mimeType" => "video/mp4", + "type" => "Link" + } + ], + "type" => "Video", + "url" => "https://peertube.-2d4c2d1630e3" + } + end + + test "fixes url for not Video object" do + object = %{ + "type" => "Text", + "url" => [ + %{ + "type" => "Link", + "mimeType" => "text/html", + "href" => "https://peertube.-2d4c2d1630e3" + }, + %{ + "type" => "Link", + "mimeType" => "text/html", + "href" => "https://peertube.-2d4c2d16377-42" + } + ] + } + + assert Transmogrifier.fix_url(object) == %{ + "type" => "Text", + "url" => "https://peertube.-2d4c2d1630e3" + } + + assert Transmogrifier.fix_url(%{"type" => "Text", "url" => []}) == %{ + "type" => "Text", + "url" => "" + } + end + + test "retunrs not modified object" do + assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"} + end + end end From fcf604fa43031be747b33c05866a192d9651322c Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 11 Sep 2019 07:23:33 +0300 Subject: [PATCH 044/272] added tests --- lib/pleroma/object/fetcher.ex | 77 ++++++++++--------- .../web/activity_pub/transmogrifier.ex | 12 +-- test/web/activity_pub/transmogrifier_test.exs | 74 ++++++++++++++++++ 3 files changed, 121 insertions(+), 42 deletions(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index c1795ae0f..2217d1eb3 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -13,6 +13,7 @@ defmodule Pleroma.Object.Fetcher do require Logger + @spec reinject_object(map()) :: {:ok, Object.t()} | {:error, any()} defp reinject_object(data) do Logger.debug("Reinjecting object #{data["id"]}") @@ -29,50 +30,54 @@ defp reinject_object(data) do # TODO: # This will create a Create activity, which we need internally at the moment. def fetch_object_from_id(id, options \\ []) do - if object = Object.get_cached_by_ap_id(id) do + with {:fetch_object, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)}, + {:fetch, {:ok, data}} <- {:fetch, fetch_and_contain_remote_object_from_id(id)}, + {:normalize, nil} <- {:normalize, Object.normalize(data, false)}, + params <- prepare_activity_params(data), + {:containment, :ok} <- {:containment, Containment.contain_origin(id, params)}, + {:ok, activity} <- Transmogrifier.handle_incoming(params, options), + {:object, _data, %Object{} = object} <- + {:object, data, Object.normalize(activity, false)} do {:ok, object} else - Logger.info("Fetching #{id} via AP") + {:containment, _} -> + {:error, "Object containment failed."} - with {:fetch, {:ok, data}} <- {:fetch, fetch_and_contain_remote_object_from_id(id)}, - {:normalize, nil} <- {:normalize, Object.normalize(data, false)}, - params <- %{ - "type" => "Create", - "to" => data["to"], - "cc" => data["cc"], - # Should we seriously keep this attributedTo thing? - "actor" => data["actor"] || data["attributedTo"], - "object" => data - }, - {:containment, :ok} <- {:containment, Containment.contain_origin(id, params)}, - {:ok, activity} <- Transmogrifier.handle_incoming(params, options), - {:object, _data, %Object{} = object} <- - {:object, data, Object.normalize(activity, false)} do + {:error, {:reject, nil}} -> + {:reject, nil} + + {:object, data, nil} -> + reinject_object(data) + + {:normalize, object = %Object{}} -> {:ok, object} - else - {:containment, _} -> - {:error, "Object containment failed."} - {:error, {:reject, nil}} -> - {:reject, nil} + {:fetch_object, %Object{} = object} -> + {:ok, object} - {:object, data, nil} -> - reinject_object(data) + _e -> + # Only fallback when receiving a fetch/normalization error with ActivityPub + Logger.info("Couldn't get object via AP, trying out OStatus fetching...") - {:normalize, object = %Object{}} -> - {:ok, object} - - _e -> - # Only fallback when receiving a fetch/normalization error with ActivityPub - Logger.info("Couldn't get object via AP, trying out OStatus fetching...") - - # FIXME: OStatus Object Containment? - case OStatus.fetch_activity_from_url(id) do - {:ok, [activity | _]} -> {:ok, Object.normalize(activity, false)} - e -> e - end - end + # FIXME: OStatus Object Containment? + case OStatus.fetch_activity_from_url(id) do + {:ok, [activity | _]} -> {:ok, Object.normalize(activity, false)} + e -> e + end end + + # end + end + + defp prepare_activity_params(data) do + %{ + "type" => "Create", + "to" => data["to"], + "cc" => data["cc"], + # Should we seriously keep this attributedTo thing? + "actor" => data["actor"] || data["attributedTo"], + "object" => data + } end def fetch_object_from_id!(id, options \\ []) do diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 93b3a1f97..18a3c3f39 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -204,7 +204,6 @@ def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachm Enum.map(attachment, fn data -> media_type = data["mediaType"] || data["mimeType"] href = data["url"] || data["href"] - url = [%{"type" => "Link", "mediaType" => media_type, "href" => href}] data @@ -216,7 +215,9 @@ def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachm end def fix_attachments(%{"attachment" => attachment} = object) when is_map(attachment) do - fix_attachments(Map.put(object, "attachment", [attachment])) + object + |> Map.put("attachment", [attachment]) + |> fix_attachments() end def fix_attachments(object), do: object @@ -725,10 +726,9 @@ def handle_incoming(_, _), do: :error @spec get_obj_helper(String.t(), Keyword.t()) :: {:ok, Object.t()} | nil def get_obj_helper(id, options \\ []) do - if object = Object.normalize(id, true, options) do - {:ok, object} - else - nil + case Object.normalize(id, true, options) do + %Object{} = object -> {:ok, object} + _ -> nil end end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 63c869d35..ab6e76056 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1613,4 +1613,78 @@ test "retunrs not modified object" do assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"} end end + + describe "get_obj_helper/2" do + test "returns nil when cannot normalize object" do + refute Transmogrifier.get_obj_helper("test-obj-id") + end + + test "returns {:ok, %Object{}} for success case" do + assert {:ok, %Object{}} = + Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873") + end + end + + describe "fix_attachments/1" do + test "returns not modified object" do + data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) + assert Transmogrifier.fix_attachments(data) == data + end + + test "returns modified object when attachment is map" do + assert Transmogrifier.fix_attachments(%{ + "attachment" => %{ + "mediaType" => "video/mp4", + "url" => "https://peertube.moe/stat-480.mp4" + } + }) == %{ + "attachment" => [ + %{ + "mediaType" => "video/mp4", + "url" => [ + %{ + "href" => "https://peertube.moe/stat-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + } + ] + } + end + + test "returns modified object when attachment is list" do + assert Transmogrifier.fix_attachments(%{ + "attachment" => [ + %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"}, + %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"} + ] + }) == %{ + "attachment" => [ + %{ + "mediaType" => "video/mp4", + "url" => [ + %{ + "href" => "https://pe.er/stat-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + }, + %{ + "href" => "https://pe.er/stat-480.mp4", + "mediaType" => "video/mp4", + "mimeType" => "video/mp4", + "url" => [ + %{ + "href" => "https://pe.er/stat-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + } + ] + } + end + end end From 007e0c1ce158bdfc11738a194944534837ae0258 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 11 Sep 2019 23:19:06 +0300 Subject: [PATCH 045/272] added tests --- .../web/activity_pub/transmogrifier.ex | 35 ++++++++++--------- .../web/activity_pub/views/user_view.ex | 7 ++-- test/web/activity_pub/transmogrifier_test.exs | 31 ++++++++++++++++ .../web/activity_pub/views/user_view_test.exs | 16 +++++++++ 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 18a3c3f39..9f699de9e 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -870,41 +870,44 @@ def add_mention_tags(object) do mentions = object |> Utils.get_notified_from_object() - |> Enum.map(fn user -> - %{"type" => "Mention", "href" => user.ap_id, "name" => "@#{user.nickname}"} - end) + |> Enum.map(&build_mention_tag/1) tags = object["tag"] || [] Map.put(object, "tag", tags ++ mentions) end - def add_emoji_tags(%User{info: %{"emoji" => _emoji} = user_info} = object) do - user_info = add_emoji_tags(user_info) + defp build_mention_tag(%{ap_id: ap_id, nickname: nickname} = _) do + %{"type" => "Mention", "href" => ap_id, "name" => "@#{nickname}"} + end - Map.put(object, :info, user_info) + def take_emoji_tags(%User{info: %{emoji: emoji} = _user_info} = _user) do + emoji + |> Enum.flat_map(&Map.to_list/1) + |> Enum.map(&build_emoji_tag/1) end # TODO: we should probably send mtime instead of unix epoch time for updated def add_emoji_tags(%{"emoji" => emoji} = object) do tags = object["tag"] || [] - out = - Enum.map(emoji, fn {name, url} -> - %{ - "icon" => %{"url" => url, "type" => "Image"}, - "name" => ":" <> name <> ":", - "type" => "Emoji", - "updated" => "1970-01-01T00:00:00Z", - "id" => url - } - end) + out = Enum.map(emoji, &build_emoji_tag/1) Map.put(object, "tag", tags ++ out) end def add_emoji_tags(object), do: object + defp build_emoji_tag({name, url}) do + %{ + "icon" => %{"url" => url, "type" => "Image"}, + "name" => ":" <> name <> ":", + "type" => "Emoji", + "updated" => "1970-01-01T00:00:00Z", + "id" => url + } + end + def set_conversation(object) do Map.put(object, "conversation", object["context"]) end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 7be734b26..8abfa1fcd 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -75,10 +75,7 @@ def render("user.json", %{user: user}) do endpoints = render("endpoints.json", %{user: user}) - user_tags = - user - |> Transmogrifier.add_emoji_tags() - |> Map.get("tag", []) + emoji_tags = Transmogrifier.take_emoji_tags(user) fields = user.info @@ -110,7 +107,7 @@ def render("user.json", %{user: user}) do }, "endpoints" => endpoints, "attachment" => fields, - "tag" => (user.info.source_data["tag"] || []) ++ user_tags + "tag" => (user.info.source_data["tag"] || []) ++ emoji_tags } |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index ab6e76056..87ef843c6 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1687,4 +1687,35 @@ test "returns modified object when attachment is list" do } end end + + describe "fix_emoji/1" do + test "returns not modified object when object not contains tags" do + data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) + assert Transmogrifier.fix_emoji(data) == data + end + + test "returns object with emoji when object contains list tags" do + assert Transmogrifier.fix_emoji(%{ + "tag" => [ + %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}, + %{"type" => "Hashtag"} + ] + }) == %{ + "emoji" => %{"bib" => "/test"}, + "tag" => [ + %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}, + %{"type" => "Hashtag"} + ] + } + end + + test "returns object with emoji when object contains map tag" do + assert Transmogrifier.fix_emoji(%{ + "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}} + }) == %{ + "emoji" => %{"bib" => "/test"}, + "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"} + } + end + end end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index fb7fd9e79..4390f9272 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -37,6 +37,22 @@ test "Renders profile fields" do } = UserView.render("user.json", %{user: user}) end + test "Renders with emoji tags" do + user = insert(:user, %{info: %{emoji: [%{"bib" => "/test"}]}}) + + assert %{ + "tag" => [ + %{ + "icon" => %{"type" => "Image", "url" => "/test"}, + "id" => "/test", + "name" => ":bib:", + "type" => "Emoji", + "updated" => "1970-01-01T00:00:00Z" + } + ] + } = UserView.render("user.json", %{user: user}) + end + test "Does not add an avatar image if the user hasn't set one" do user = insert(:user) {:ok, user} = User.ensure_keys_present(user) From 4f548cb2b7b4a16a956a4f4a0ff64d279777925e Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 12 Sep 2019 09:59:34 +0300 Subject: [PATCH 046/272] added test for Ostatus --- .../web/activity_pub/transmogrifier.ex | 10 +- lib/pleroma/web/ostatus/ostatus.ex | 99 ++++++++----------- lib/pleroma/web/ostatus/ostatus_controller.ex | 12 +-- test/web/ostatus/ostatus_test.exs | 14 +++ 4 files changed, 68 insertions(+), 67 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 468961bd0..acd61bda3 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -1049,8 +1049,8 @@ def upgrade_user_from_ap_id(ap_id) do with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id), {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id), already_ap <- User.ap_enabled?(user), - {:ok, user} <- user |> User.upgrade_changeset(data) |> User.update_and_set_cache() do - unless already_ap do + {:ok, user} <- upgrade_user(user, data) do + if not already_ap do PleromaJobQueue.enqueue(:transmogrifier, __MODULE__, [:user_upgrade, user]) end @@ -1061,6 +1061,12 @@ def upgrade_user_from_ap_id(ap_id) do end end + defp upgrade_user(user, data) do + user + |> User.upgrade_changeset(data) + |> User.update_and_set_cache() + end + def maybe_retire_websub(ap_id) do # some sanity checks if is_binary(ap_id) && String.length(ap_id) > 8 do diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 331cbc0b7..5de1ceef3 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -3,14 +3,12 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus do - import Ecto.Query import Pleroma.Web.XML require Logger alias Pleroma.Activity alias Pleroma.HTTP alias Pleroma.Object - alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.ActivityPub.ActivityPub @@ -38,21 +36,13 @@ def is_representable?(%Activity{} = activity) do end end - def feed_path(user) do - "#{user.ap_id}/feed.atom" - end + def feed_path(user), do: "#{user.ap_id}/feed.atom" - def pubsub_path(user) do - "#{Web.base_url()}/push/hub/#{user.nickname}" - end + def pubsub_path(user), do: "#{Web.base_url()}/push/hub/#{user.nickname}" - def salmon_path(user) do - "#{user.ap_id}/salmon" - end + def salmon_path(user), do: "#{user.ap_id}/salmon" - def remote_follow_path do - "#{Web.base_url()}/ostatus_subscribe?acct={uri}" - end + def remote_follow_path, do: "#{Web.base_url()}/ostatus_subscribe?acct={uri}" def handle_incoming(xml_string, options \\ []) do with doc when doc != :error <- parse_document(xml_string) do @@ -217,10 +207,9 @@ def get_content(entry) do Get the cw that mastodon uses. """ def get_cw(entry) do - with cw when not is_nil(cw) <- string_from_xpath("/*/summary", entry) do - cw - else - _e -> nil + case string_from_xpath("/*/summary", entry) do + cw when not is_nil(cw) -> cw + _ -> nil end end @@ -232,19 +221,17 @@ def get_tags(entry) do end def maybe_update(doc, user) do - if "true" == string_from_xpath("//author[1]/ap_enabled", doc) do - Transmogrifier.upgrade_user_from_ap_id(user.ap_id) - else - maybe_update_ostatus(doc, user) + case string_from_xpath("//author[1]/ap_enabled", doc) do + "true" -> + Transmogrifier.upgrade_user_from_ap_id(user.ap_id) + + _ -> + maybe_update_ostatus(doc, user) end end def maybe_update_ostatus(doc, user) do - old_data = %{ - avatar: user.avatar, - bio: user.bio, - name: user.name - } + old_data = Map.take(user, [:bio, :avatar, :name]) with false <- user.local, avatar <- make_avatar_object(doc), @@ -279,38 +266,37 @@ def find_make_or_update_actor(doc) do end end + @spec find_or_make_user(String.t()) :: {:ok, User.t()} def find_or_make_user(uri) do - query = from(user in User, where: user.ap_id == ^uri) - - user = Repo.one(query) - - if is_nil(user) do - make_user(uri) - else - {:ok, user} + case User.get_by_ap_id(uri) do + %User{} = user -> {:ok, user} + _ -> make_user(uri) end end + @spec make_user(String.t(), boolean()) :: {:ok, User.t()} | {:error, any()} def make_user(uri, update \\ false) do with {:ok, info} <- gather_user_info(uri) do - data = %{ - name: info["name"], - nickname: info["nickname"] <> "@" <> info["host"], - ap_id: info["uri"], - info: info, - avatar: info["avatar"], - bio: info["bio"] - } - with false <- update, - %User{} = user <- User.get_cached_by_ap_id(data.ap_id) do + %User{} = user <- User.get_cached_by_ap_id(info["uri"]) do {:ok, user} else - _e -> User.insert_or_update_user(data) + _e -> User.insert_or_update_user(build_user_data(info)) end end end + defp build_user_data(info) do + %{ + name: info["name"], + nickname: info["nickname"] <> "@" <> info["host"], + ap_id: info["uri"], + info: info, + avatar: info["avatar"], + bio: info["bio"] + } + end + # TODO: Just takes the first one for now. def make_avatar_object(author_doc, rel \\ "avatar") do href = string_from_xpath("//author[1]/link[@rel=\"#{rel}\"]/@href", author_doc) @@ -319,23 +305,23 @@ def make_avatar_object(author_doc, rel \\ "avatar") do if href do %{ "type" => "Image", - "url" => [ - %{ - "type" => "Link", - "mediaType" => type, - "href" => href - } - ] + "url" => [%{"type" => "Link", "mediaType" => type, "href" => href}] } else nil end end + @spec gather_user_info(String.t()) :: {:ok, map()} | {:error, any()} def gather_user_info(username) do with {:ok, webfinger_data} <- WebFinger.finger(username), {:ok, feed_data} <- Websub.gather_feed_data(webfinger_data["topic"]) do - {:ok, Map.merge(webfinger_data, feed_data) |> Map.put("fqn", username)} + data = + webfinger_data + |> Map.merge(feed_data) + |> Map.put("fqn", username) + + {:ok, data} else e -> Logger.debug(fn -> "Couldn't gather info for #{username}" end) @@ -371,10 +357,7 @@ def get_atom_url(body) do def fetch_activity_from_atom_url(url, options \\ []) do with true <- String.starts_with?(url, "http"), {:ok, %{body: body, status: code}} when code in 200..299 <- - HTTP.get( - url, - [{:Accept, "application/atom+xml"}] - ) do + HTTP.get(url, [{:Accept, "application/atom+xml"}]) do Logger.debug("Got document from #{url}, handling...") handle_incoming(body, options) else diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 07e2a4c2d..64b2c64b3 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -55,12 +55,11 @@ def feed_redirect(conn, %{"nickname" => nickname}) do def feed(conn, %{"nickname" => nickname} = params) do with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do - query_params = - Map.take(params, ["max_id"]) - |> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id}) - activities = - ActivityPub.fetch_public_activities(query_params) + params + |> Map.take(["max_id"]) + |> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id}) + |> ActivityPub.fetch_public_activities() |> Enum.reverse() response = @@ -98,8 +97,7 @@ def salmon_incoming(conn, _) do Federator.incoming_doc(doc) - conn - |> send_resp(200, "") + send_resp(conn, 200, "") end def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index 803a97695..ff00c53ee 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -628,4 +628,18 @@ test "Article objects are not representable" do refute OStatus.is_representable?(note_activity) end end + + describe "make_user/2" do + test "creates new user" do + {:ok, user} = OStatus.make_user("https://social.heldscal.la/user/23211") + + created_user = + User + |> Repo.get_by(ap_id: "https://social.heldscal.la/user/23211") + |> Map.put(:last_digest_emailed_at, nil) + + assert user.info + assert user == created_user + end + end end From 769fb778d41df77c2514b5e3c663f3f624c0a266 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 12 Sep 2019 21:37:36 +0300 Subject: [PATCH 047/272] Track object/create activity fetches --- lib/pleroma/delivery.ex | 58 +++++++++++++ lib/pleroma/plugs/cache.ex | 16 +++- lib/pleroma/user.ex | 10 +++ .../activity_pub/activity_pub_controller.ex | 29 ++++++- .../20190912065617_create_deliveries.exs | 12 +++ .../activity_pub_controller_test.exs | 83 +++++++++++++++++++ 6 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 lib/pleroma/delivery.ex create mode 100644 priv/repo/migrations/20190912065617_create_deliveries.exs diff --git a/lib/pleroma/delivery.ex b/lib/pleroma/delivery.ex new file mode 100644 index 000000000..f9a9e35cd --- /dev/null +++ b/lib/pleroma/delivery.ex @@ -0,0 +1,58 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Delivery do + use Ecto.Schema + + alias Pleroma.Delivery + alias Pleroma.FlakeId + alias Pleroma.User + alias Pleroma.Repo + alias Pleroma.Object + alias Pleroma.User + + import Ecto.Changeset + import Ecto.Query + + schema "deliveries" do + belongs_to(:user, User, type: FlakeId) + belongs_to(:object, Object) + end + + def changeset(delivery, params \\ %{}) do + delivery + |> cast(params, [:user_id, :object_id]) + |> foreign_key_constraint(:object_id) + |> foreign_key_constraint(:user_id) + |> unique_constraint(:user_id, name: :deliveries_user_id_object_id_index) + end + + def create(object_id, user_id) do + %Delivery{} + |> changeset(%{user_id: user_id, object_id: object_id}) + |> Repo.insert() + end + + def get(object_id, user_id) do + from(d in Delivery, where: d.user_id == ^user_id and d.object_id == ^object_id) + |> Repo.one() + end + + def get_or_create(object_id, user_id) do + case get(object_id, user_id) do + %Delivery{} = delivery -> {:ok, delivery} + nil -> create(object_id, user_id) + end + end + + def delete_all_by_object_id(object_id) do + from(d in Delivery, where: d.object_id == ^object_id) + |> Repo.delete_all() + end + + def get_all_by_object_id(object_id) do + from(d in Delivery, where: d.object_id == ^object_id) + |> Repo.all() + end +end diff --git a/lib/pleroma/plugs/cache.ex b/lib/pleroma/plugs/cache.ex index a81a861d0..42d77fc1f 100644 --- a/lib/pleroma/plugs/cache.ex +++ b/lib/pleroma/plugs/cache.ex @@ -20,6 +20,7 @@ defmodule Pleroma.Plugs.Cache do - `ttl`: An expiration time (time-to-live). This value should be in milliseconds or `nil` to disable expiration. Defaults to `nil`. - `query_params`: Take URL query string into account (`true`), ignore it (`false`) or limit to specific params only (list). Defaults to `true`. + - `tracking_fun`: A function that is called on successfull responses, no matter if the request is cached or not. It should accept a conn as the first argument and the value assigned to `tracking_fun_data` as the second. Additionally, you can overwrite the TTL inside a controller action by assigning `cache_ttl` to the connection struct: @@ -56,6 +57,10 @@ def call(%{method: "GET"} = conn, opts) do {:ok, nil} -> cache_resp(conn, opts) + {:ok, {content_type, body, tracking_fun_data}} -> + conn = opts.tracking_fun(conn, tracking_fun_data) + send_cached(conn, {content_type, body}) + {:ok, record} -> send_cached(conn, record) @@ -90,7 +95,16 @@ defp cache_resp(conn, opts) do content_type = content_type(conn) record = {content_type, body} - Cachex.put(:web_resp_cache, key, record, ttl: ttl) + conn = + unless opts[:tracking_fun] do + Cachex.put(:web_resp_cache, key, {content_type, body}, ttl: ttl) + conn + else + tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil) + Cachex.put(:web_resp_cache, {content_type, body, tracking_fun_data}, record, ttl: ttl) + + opts.tracking_fun.(conn, tracking_fun_data) + end put_resp_header(conn, "x-cache", "MISS from Pleroma") diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3aa245f2a..9614acdab 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -11,6 +11,7 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Ecto.Multi alias Pleroma.Activity + alias Pleroma.Delivery alias Pleroma.Keys alias Pleroma.Notification alias Pleroma.Object @@ -61,6 +62,7 @@ defmodule Pleroma.User do field(:last_digest_emailed_at, :naive_datetime) has_many(:notifications, Notification) has_many(:registrations, Registration) + has_many(:deliveries, Delivery) embeds_one(:info, User.Info) timestamps() @@ -1624,4 +1626,12 @@ defp put_password_hash(changeset), do: changeset def is_internal_user?(%User{nickname: nil}), do: true def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true def is_internal_user?(_), do: false + + def get_delivered_users_by_object_id(object_id) do + from(u in User, + inner_join: delivery in assoc(u, :deliveries), + where: delivery.object_id == ^object_id + ) + |> Repo.all() + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 705dbc1c2..009260d3f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do use Pleroma.Web, :controller alias Pleroma.Activity + alias Pleroma.Delivery alias Pleroma.Object alias Pleroma.Object.Fetcher alias Pleroma.User @@ -23,7 +24,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do action_fallback(:errors) - plug(Pleroma.Plugs.Cache, [query_params: false] when action in [:activity, :object]) + plug( + Pleroma.Plugs.Cache, + [ + query_params: false, + tracking_fun: &Pleroma.Web.ActivityPub.ActivityPubController.track_object_fetch/2 + ] + when action in [:activity, :object] + ) + plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay]) plug(:set_requester_reachable when action in [:inbox]) plug(:relay_active? when action in [:relay]) @@ -54,6 +63,7 @@ def object(conn, %{"uuid" => uuid}) do %Object{} = object <- Object.get_cached_by_ap_id(ap_id), {_, true} <- {:public?, Visibility.is_public?(object)} do conn + |> assign(:tracking_fun_data, object.id) |> set_cache_ttl_for(object) |> put_resp_content_type("application/activity+json") |> put_view(ObjectView) @@ -64,6 +74,15 @@ def object(conn, %{"uuid" => uuid}) do end end + def track_object_fetch(conn, object_id) do + case conn.assigns[:user] do + %User{id: user_id} -> Delivery.create(object_id, user_id) + _ -> nil + end + + conn + end + def object_likes(conn, %{"uuid" => uuid, "page" => page}) do with ap_id <- o_status_url(conn, :object, uuid), %Object{} = object <- Object.get_cached_by_ap_id(ap_id), @@ -99,6 +118,7 @@ def activity(conn, %{"uuid" => uuid}) do %Activity{} = activity <- Activity.normalize(ap_id), {_, true} <- {:public?, Visibility.is_public?(activity)} do conn + |> maybe_set_tracking_data(activity) |> set_cache_ttl_for(activity) |> put_resp_content_type("application/activity+json") |> put_view(ObjectView) @@ -109,6 +129,13 @@ def activity(conn, %{"uuid" => uuid}) do end end + defp maybe_set_tracking_data(conn, %Activity{data: %{"type" => "Create"}} = activity) do + object_id = Object.normalize(activity).id + assign(conn, :tracking_fun_data, object_id) + end + + defp maybe_set_tracking_data(conn, _activity), do: assign(conn, :tracking_fun_data, nil) + defp set_cache_ttl_for(conn, %Activity{object: object}) do set_cache_ttl_for(conn, object) end diff --git a/priv/repo/migrations/20190912065617_create_deliveries.exs b/priv/repo/migrations/20190912065617_create_deliveries.exs new file mode 100644 index 000000000..92ca5650a --- /dev/null +++ b/priv/repo/migrations/20190912065617_create_deliveries.exs @@ -0,0 +1,12 @@ +defmodule Pleroma.Repo.Migrations.CreateDeliveries do + use Ecto.Migration + + def change do + create_if_not_exists table(:deliveries) do + add(:object_id, references(:objects, type: :id)) + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + end + create_if_not_exists index(:deliveries, :object_id, name: :deliveries_object_id) + create_if_not_exists(unique_index(:deliveries, [:user_id, :object_id])) + end +end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 9698c7099..0bab555b5 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do use Pleroma.Web.ConnCase import Pleroma.Factory alias Pleroma.Activity + alias Pleroma.Delivery alias Pleroma.Instances alias Pleroma.Object alias Pleroma.User @@ -885,4 +886,86 @@ test "it works for more than 10 users", %{conn: conn} do assert result["totalItems"] == 15 end end + + describe "delivery tracking" do + test "it tracks a signed object fetch", %{conn: conn} do + user = insert(:user, local: false) + activity = insert(:note_activity) + object = Object.normalize(activity) + + object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) + + conn + |> put_req_header("accept", "application/activity+json") + |> assign(:user, user) + |> get(object_path) + |> json_response(200) + + assert Delivery.get(object.id, user.id) + end + + test "it tracks a signed activity fetch", %{conn: conn} do + user = insert(:user, local: false) + activity = insert(:note_activity) + object = Object.normalize(activity) + + activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) + + conn + |> put_req_header("accept", "application/activity+json") + |> assign(:user, user) + |> get(activity_path) + |> json_response(200) + + assert Delivery.get(object.id, user.id) + end + + test "it tracks a signed object fetch when the json is cached", %{conn: conn} do + user = insert(:user, local: false) + other_user = insert(:user, local: false) + activity = insert(:note_activity) + object = Object.normalize(activity) + + object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) + + conn + |> put_req_header("accept", "application/activity+json") + |> assign(:user, user) + |> get(object_path) + |> json_response(200) + + build_conn() + |> put_req_header("accept", "application/activity+json") + |> assign(:user, other_user) + |> get(object_path) + |> json_response(200) + + assert Delivery.get(object.id, user.id) + assert Delivery.get(object.id, other_user.id) + end + + test "it tracks a signed activity fetch when the json is cached", %{conn: conn} do + user = insert(:user, local: false) + other_user = insert(:user, local: false) + activity = insert(:note_activity) + object = Object.normalize(activity) + + activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) + + conn + |> put_req_header("accept", "application/activity+json") + |> assign(:user, user) + |> get(activity_path) + |> json_response(200) + + build_conn() + |> put_req_header("accept", "application/activity+json") + |> assign(:user, other_user) + |> get(activity_path) + |> json_response(200) + + assert Delivery.get(object.id, user.id) + assert Delivery.get(object.id, other_user.id) + end + end end From dabc4a00f5cf08dac75f701457a24fce8735175f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 12 Sep 2019 22:10:15 +0300 Subject: [PATCH 048/272] Put the cache with the right key when using a tracking function --- lib/pleroma/plugs/cache.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/plugs/cache.ex b/lib/pleroma/plugs/cache.ex index 42d77fc1f..50b534e7b 100644 --- a/lib/pleroma/plugs/cache.ex +++ b/lib/pleroma/plugs/cache.ex @@ -58,7 +58,8 @@ def call(%{method: "GET"} = conn, opts) do cache_resp(conn, opts) {:ok, {content_type, body, tracking_fun_data}} -> - conn = opts.tracking_fun(conn, tracking_fun_data) + conn = opts.tracking_fun.(conn, tracking_fun_data) + send_cached(conn, {content_type, body}) {:ok, record} -> @@ -93,7 +94,6 @@ defp cache_resp(conn, opts) do ttl = Map.get(conn.assigns, :cache_ttl, opts.ttl) key = cache_key(conn, opts) content_type = content_type(conn) - record = {content_type, body} conn = unless opts[:tracking_fun] do @@ -101,7 +101,7 @@ defp cache_resp(conn, opts) do conn else tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil) - Cachex.put(:web_resp_cache, {content_type, body, tracking_fun_data}, record, ttl: ttl) + Cachex.put(:web_resp_cache, key, {content_type, body, tracking_fun_data}, ttl: ttl) opts.tracking_fun.(conn, tracking_fun_data) end From b0e60580215e26caae6452099fa1fbace525937c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 12 Sep 2019 22:40:53 +0300 Subject: [PATCH 049/272] Parse http signature for request to objects/activities --- lib/pleroma/plugs/http_signature.ex | 3 ++- lib/pleroma/web/router.ex | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex index d87fa52fa..23d22a712 100644 --- a/lib/pleroma/plugs/http_signature.ex +++ b/lib/pleroma/plugs/http_signature.ex @@ -15,7 +15,8 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do end def call(conn, _opts) do - [signature | _] = get_req_header(conn, "signature") + headers = get_req_header(conn, "signature") + signature = Enum.at(headers, 0) if signature do # set (request-target) header to the appropriate value diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 7cd59acb2..badc7e048 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -135,6 +135,7 @@ defmodule Pleroma.Web.Router do pipeline :http_signature do plug(Pleroma.Web.Plugs.HTTPSignaturePlug) + plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug) end scope "/api/pleroma", Pleroma.Web.TwitterAPI do @@ -513,6 +514,7 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web do pipe_through(:ostatus) + pipe_through(:http_signature) get("/objects/:uuid", OStatus.OStatusController, :object) get("/activities/:uuid", OStatus.OStatusController, :activity) From 58b17196fa3f2583db5ee0534766350ed25727e0 Mon Sep 17 00:00:00 2001 From: Maksim Date: Fri, 13 Sep 2019 03:58:58 +0000 Subject: [PATCH 050/272] Apply suggestion to test/web/mastodon_api/mastodon_api_controller_test.exs --- test/web/mastodon_api/mastodon_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index a331d6455..7b337044c 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1552,7 +1552,7 @@ test "returns the relationships for the current user", %{conn: conn} do assert to_string(other_user.id) == relationship["id"] end - test "returns an empty list when bad request", %{conn: conn} do + test "returns an empty list on a bad request", %{conn: conn} do user = insert(:user) conn = From d8a178274bd1eb642270e52f207849014cba12bc Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 13 Sep 2019 07:12:34 +0300 Subject: [PATCH 051/272] fix Activity.get_by_id --- lib/pleroma/activity.ex | 15 +++++++++++---- .../mastodon_api/mastodon_api_controller_test.exs | 9 +++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 2d4e9da0c..56c51aef8 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -150,11 +150,18 @@ def get_by_ap_id_with_object(ap_id) do ) end + @spec get_by_id(String.t()) :: Activity.t() | nil def get_by_id(id) do - Activity - |> where([a], a.id == ^id) - |> restrict_deactivated_users() - |> Repo.one() + case Pleroma.FlakeId.is_flake_id?(id) do + true -> + Activity + |> where([a], a.id == ^id) + |> restrict_deactivated_users() + |> Repo.one() + + _ -> + nil + end end def get_by_id_with_object(id) do diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 7b337044c..35c2236c8 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2864,6 +2864,15 @@ test "returns empty object when id invalid", %{conn: conn} do assert response == %{} end + + test "returns empty object when id isn't FlakeID", %{conn: conn} do + response = + conn + |> get("/api/v1/statuses/3ebbadd1-eb14-4e20-8118/card") + |> json_response(200) + + assert response == %{} + end end test "bookmarks" do From 39dc9b470c7ad8348a13f181039f11d14a42fa2b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 3 Sep 2019 21:58:30 +0700 Subject: [PATCH 052/272] Cleanup Pleroma.Activity and Pleroma.Web.ActivityPub.Utils --- lib/pleroma/activity.ex | 193 ++++++-------------------- lib/pleroma/activity/queries.ex | 32 ++++- lib/pleroma/user.ex | 2 +- lib/pleroma/web/activity_pub/utils.ex | 167 ++++++++-------------- test/user_test.exs | 2 +- 5 files changed, 128 insertions(+), 268 deletions(-) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 44f1e3011..ec558168a 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Activity do use Ecto.Schema alias Pleroma.Activity + alias Pleroma.Activity.Queries alias Pleroma.ActivityExpiration alias Pleroma.Bookmark alias Pleroma.Notification @@ -65,8 +66,8 @@ defmodule Pleroma.Activity do timestamps() end - def with_joined_object(query) do - join(query, :inner, [activity], o in Object, + def with_joined_object(query, join_type \\ :inner) do + join(query, join_type, [activity], o in Object, on: fragment( "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", @@ -78,10 +79,10 @@ def with_joined_object(query) do ) end - def with_preloaded_object(query) do + def with_preloaded_object(query, join_type \\ :inner) do query |> has_named_binding?(:object) - |> if(do: query, else: with_joined_object(query)) + |> if(do: query, else: with_joined_object(query, join_type)) |> preload([activity, object: object], object: object) end @@ -107,12 +108,9 @@ def with_set_thread_muted_field(query, %User{} = user) do def with_set_thread_muted_field(query, _), do: query def get_by_ap_id(ap_id) do - Repo.one( - from( - activity in Activity, - where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)) - ) - ) + ap_id + |> Queries.by_ap_id() + |> Repo.one() end def get_bookmark(%Activity{} = activity, %User{} = user) do @@ -133,21 +131,10 @@ def change(struct, params \\ %{}) do end def get_by_ap_id_with_object(ap_id) do - Repo.one( - from( - activity in Activity, - where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)), - left_join: o in Object, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", - o.data, - activity.data, - activity.data - ), - preload: [object: o] - ) - ) + ap_id + |> Queries.by_ap_id() + |> with_preloaded_object(:left) + |> Repo.one() end def get_by_id(id) do @@ -158,18 +145,9 @@ def get_by_id(id) do end def get_by_id_with_object(id) do - from(activity in Activity, - where: activity.id == ^id, - inner_join: o in Object, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", - o.data, - activity.data, - activity.data - ), - preload: [object: o] - ) + Activity + |> where(id: ^id) + |> with_preloaded_object() |> Repo.one() end @@ -180,51 +158,21 @@ def all_by_ids_with_object(ids) do |> Repo.all() end - def by_object_ap_id(ap_id) do - from( - activity in Activity, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^to_string(ap_id) - ) - ) + @doc """ + Accepts `ap_id` or list of `ap_id`. + Returns a query. + """ + @spec create_by_object_ap_id(String.t() | [String.t()]) :: Ecto.Queryable.t() + def create_by_object_ap_id(ap_id) do + ap_id + |> Queries.by_object_id() + |> Queries.by_type("Create") end - def create_by_object_ap_id(ap_ids) when is_list(ap_ids) do - from( - activity in Activity, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)", - activity.data, - activity.data, - ^ap_ids - ), - where: fragment("(?)->>'type' = 'Create'", activity.data) - ) - end - - def create_by_object_ap_id(ap_id) when is_binary(ap_id) do - from( - activity in Activity, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^to_string(ap_id) - ), - where: fragment("(?)->>'type' = 'Create'", activity.data) - ) - end - - def create_by_object_ap_id(_), do: nil - def get_all_create_by_object_ap_id(ap_id) do - Repo.all(create_by_object_ap_id(ap_id)) + ap_id + |> create_by_object_ap_id() + |> Repo.all() end def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do @@ -235,54 +183,17 @@ def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do def get_create_by_object_ap_id(_), do: nil - def create_by_object_ap_id_with_object(ap_ids) when is_list(ap_ids) do - from( - activity in Activity, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)", - activity.data, - activity.data, - ^ap_ids - ), - where: fragment("(?)->>'type' = 'Create'", activity.data), - inner_join: o in Object, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", - o.data, - activity.data, - activity.data - ), - preload: [object: o] - ) + @doc """ + Accepts `ap_id` or list of `ap_id`. + Returns a query. + """ + @spec create_by_object_ap_id_with_object(String.t() | [String.t()]) :: Ecto.Queryable.t() + def create_by_object_ap_id_with_object(ap_id) do + ap_id + |> create_by_object_ap_id() + |> with_preloaded_object() end - def create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do - from( - activity in Activity, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^to_string(ap_id) - ), - where: fragment("(?)->>'type' = 'Create'", activity.data), - inner_join: o in Object, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", - o.data, - activity.data, - activity.data - ), - preload: [object: o] - ) - end - - def create_by_object_ap_id_with_object(_), do: nil - def get_create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do ap_id |> create_by_object_ap_id_with_object() @@ -306,7 +217,8 @@ def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id) def normalize(_), do: nil def delete_by_ap_id(id) when is_binary(id) do - by_object_ap_id(id) + id + |> Queries.by_object_id() |> select([u], u) |> Repo.delete_all() |> elem(1) @@ -350,31 +262,10 @@ def all_by_actor_and_id(actor, status_ids) do end def follow_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do - from( - a in Activity, - where: - fragment( - "? ->> 'type' = 'Follow'", - a.data - ), - where: - fragment( - "? ->> 'state' = 'pending'", - a.data - ), - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - a.data, - a.data, - ^ap_id - ) - ) - end - - @spec query_by_actor(actor()) :: Ecto.Query.t() - def query_by_actor(actor) do - from(a in Activity, where: a.actor == ^actor) + ap_id + |> Queries.by_object_id() + |> Queries.by_type("Follow") + |> where([a], fragment("? ->> 'state' = 'pending'", a.data)) end def restrict_deactivated_users(query) do diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex index aa5b29566..13fa33831 100644 --- a/lib/pleroma/activity/queries.ex +++ b/lib/pleroma/activity/queries.ex @@ -13,6 +13,14 @@ defmodule Pleroma.Activity.Queries do alias Pleroma.Activity + @spec by_ap_id(query, String.t()) :: query + def by_ap_id(query \\ Activity, ap_id) do + from( + activity in query, + where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)) + ) + end + @spec by_actor(query, String.t()) :: query def by_actor(query \\ Activity, actor) do from( @@ -21,8 +29,23 @@ def by_actor(query \\ Activity, actor) do ) end - @spec by_object_id(query, String.t()) :: query - def by_object_id(query \\ Activity, object_id) do + @spec by_object_id(query, String.t() | [String.t()]) :: query + def by_object_id(query \\ Activity, object_id) + + def by_object_id(query, object_ids) when is_list(object_ids) do + from( + activity in query, + where: + fragment( + "coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)", + activity.data, + activity.data, + ^object_ids + ) + ) + end + + def by_object_id(query, object_id) when is_binary(object_id) do from(activity in query, where: fragment( @@ -41,9 +64,4 @@ def by_type(query \\ Activity, activity_type) do where: fragment("(?)->>'type' = ?", activity.data, ^activity_type) ) end - - @spec limit(query, pos_integer()) :: query - def limit(query \\ Activity, limit) do - from(activity in query, limit: ^limit) - end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3aa245f2a..ceca11def 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1219,7 +1219,7 @@ def follow_import(%User{} = follower, followed_identifiers) when is_list(followe def delete_user_activities(%User{ap_id: ap_id} = user) do ap_id - |> Activity.query_by_actor() + |> Activity.Queries.by_actor() |> RepoStreamer.chunk_stream(50) |> Stream.each(fn activities -> Enum.each(activities, &delete_activity(&1)) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index c9c0c3763..47917f5d3 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -85,15 +85,13 @@ defp extract_list(lst) when is_list(lst), do: lst defp extract_list(_), do: [] def maybe_splice_recipient(ap_id, params) do - need_splice = + need_splice? = !recipient_in_collection(ap_id, params["to"]) && !recipient_in_collection(ap_id, params["cc"]) - cc_list = extract_list(params["cc"]) - - if need_splice do - params - |> Map.put("cc", [ap_id | cc_list]) + if need_splice? do + cc_list = extract_list(params["cc"]) + Map.put(params, "cc", [ap_id | cc_list]) else params end @@ -139,7 +137,7 @@ def get_notified_from_object(%{"type" => type} = object) when type in @supported "object" => object } - Notification.get_notified_from_activity(%Activity{data: fake_create_activity}, false) + get_notified_from_object(fake_create_activity) end def get_notified_from_object(object) do @@ -188,9 +186,9 @@ def maybe_federate(_), do: :ok Adds an id and a published data if they aren't there, also adds it to an included object """ - def lazy_put_activity_defaults(map, fake \\ false) do + def lazy_put_activity_defaults(map, fake? \\ false) do map = - unless fake do + if not fake? do %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) map @@ -207,7 +205,7 @@ def lazy_put_activity_defaults(map, fake \\ false) do end if is_map(map["object"]) do - object = lazy_put_object_defaults(map["object"], map, fake) + object = lazy_put_object_defaults(map["object"], map, fake?) %{map | "object" => object} else map @@ -217,9 +215,9 @@ def lazy_put_activity_defaults(map, fake \\ false) do @doc """ Adds an id and published date if they aren't there. """ - def lazy_put_object_defaults(map, activity \\ %{}, fake) + def lazy_put_object_defaults(map, activity \\ %{}, fake?) - def lazy_put_object_defaults(map, activity, true = _fake) do + def lazy_put_object_defaults(map, activity, true = _fake?) do map |> Map.put_new_lazy("published", &make_date/0) |> Map.put_new("id", "pleroma:fake_object_id") @@ -228,7 +226,7 @@ def lazy_put_object_defaults(map, activity, true = _fake) do |> Map.put_new("context_id", activity["context_id"]) end - def lazy_put_object_defaults(map, activity, _fake) do + def lazy_put_object_defaults(map, activity, _fake?) do map |> Map.put_new_lazy("id", &generate_object_id/0) |> Map.put_new_lazy("published", &make_date/0) @@ -242,9 +240,7 @@ def lazy_put_object_defaults(map, activity, _fake) do def insert_full_object(%{"object" => %{"type" => type} = object_data} = map) when is_map(object_data) and type in @supported_object_types do with {:ok, object} <- Object.create(object_data) do - map = - map - |> Map.put("object", object.data["id"]) + map = Map.put(map, "object", object.data["id"]) {:ok, map, object} end @@ -263,7 +259,7 @@ def get_existing_like(actor, %{data: %{"id" => id}}) do |> Activity.Queries.by_actor() |> Activity.Queries.by_object_id(id) |> Activity.Queries.by_type("Like") - |> Activity.Queries.limit(1) + |> limit(1) |> Repo.one() end @@ -380,12 +376,11 @@ def update_follow_state( %Activity{data: %{"actor" => actor, "object" => object}} = activity, state ) do - with new_data <- - activity.data - |> Map.put("state", state), - changeset <- Changeset.change(activity, data: new_data), - {:ok, activity} <- Repo.update(changeset), - _ <- User.set_follow_state_cache(actor, object, state) do + new_data = Map.put(activity.data, "state", state) + changeset = Changeset.change(activity, data: new_data) + + with {:ok, activity} <- Repo.update(changeset) do + User.set_follow_state_cache(actor, object, state) {:ok, activity} end end @@ -410,28 +405,14 @@ def make_follow_data( end def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do - query = - from( - activity in Activity, - where: - fragment( - "? ->> 'type' = 'Follow'", - activity.data - ), - where: activity.actor == ^follower_id, - # this is to use the index - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^followed_id - ), - order_by: [fragment("? desc nulls last", activity.id)], - limit: 1 - ) - - Repo.one(query) + "Follow" + |> Activity.Queries.by_type() + |> where(actor: ^follower_id) + # this is to use the index + |> Activity.Queries.by_object_id(followed_id) + |> order_by([activity], fragment("? desc nulls last", activity.id)) + |> limit(1) + |> Repo.one() end #### Announce-related helpers @@ -439,23 +420,13 @@ def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do @doc """ Retruns an existing announce activity if the notice has already been announced """ - def get_existing_announce(actor, %{data: %{"id" => id}}) do - query = - from( - activity in Activity, - where: activity.actor == ^actor, - # this is to use the index - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^id - ), - where: fragment("(?)->>'type' = 'Announce'", activity.data) - ) - - Repo.one(query) + def get_existing_announce(actor, %{data: %{"id" => ap_id}}) do + "Announce" + |> Activity.Queries.by_type() + |> where(actor: ^actor) + # this is to use the index + |> Activity.Queries.by_object_id(ap_id) + |> Repo.one() end @doc """ @@ -538,11 +509,13 @@ def add_announce_to_object( object ) do announcements = - if is_list(object.data["announcements"]), do: object.data["announcements"], else: [] + if is_list(object.data["announcements"]) do + Enum.uniq([actor | object.data["announcements"]]) + else + [actor] + end - with announcements <- [actor | announcements] |> Enum.uniq() do - update_element_in_object("announcement", announcements, object) - end + update_element_in_object("announcement", announcements, object) end def add_announce_to_object(_, object), do: {:ok, object} @@ -570,28 +543,14 @@ def make_unfollow_data(follower, followed, follow_activity, activity_id) do #### Block-related helpers def fetch_latest_block(%User{ap_id: blocker_id}, %User{ap_id: blocked_id}) do - query = - from( - activity in Activity, - where: - fragment( - "? ->> 'type' = 'Block'", - activity.data - ), - where: activity.actor == ^blocker_id, - # this is to use the index - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^blocked_id - ), - order_by: [fragment("? desc nulls last", activity.id)], - limit: 1 - ) - - Repo.one(query) + "Block" + |> Activity.Queries.by_type() + |> where(actor: ^blocker_id) + # this is to use the index + |> Activity.Queries.by_object_id(blocked_id) + |> order_by([activity], fragment("? desc nulls last", activity.id)) + |> limit(1) + |> Repo.one() end def make_block_data(blocker, blocked, activity_id) do @@ -695,11 +654,11 @@ def fetch_ordered_collection(from, pages_left, acc \\ []) do #### Report-related helpers def update_report_state(%Activity{} = activity, state) when state in @supported_report_states do - with new_data <- Map.put(activity.data, "state", state), - changeset <- Changeset.change(activity, data: new_data), - {:ok, activity} <- Repo.update(changeset) do - {:ok, activity} - end + new_data = Map.put(activity.data, "state", state) + + activity + |> Changeset.change(data: new_data) + |> Repo.update() end def update_report_state(_, _), do: {:error, "Unsupported state"} @@ -766,21 +725,13 @@ defp get_updated_targets( end def get_existing_votes(actor, %{data: %{"id" => id}}) do - query = - from( - [activity, object: object] in Activity.with_preloaded_object(Activity), - where: fragment("(?)->>'type' = 'Create'", activity.data), - where: fragment("(?)->>'actor' = ?", activity.data, ^actor), - where: - fragment( - "(?)->>'inReplyTo' = ?", - object.data, - ^to_string(id) - ), - where: fragment("(?)->>'type' = 'Answer'", object.data) - ) - - Repo.all(query) + actor + |> Activity.Queries.by_actor() + |> Activity.Queries.by_type("Create") + |> Activity.with_preloaded_object() + |> where([a, object: o], fragment("(?)->>'inReplyTo' = ?", o.data, ^to_string(id))) + |> where([a, object: o], fragment("(?)->>'type' = 'Answer'", o.data)) + |> Repo.all() end defp maybe_put(map, _key, nil), do: map diff --git a/test/user_test.exs b/test/user_test.exs index a25b72f4e..206258fee 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1081,7 +1081,7 @@ test "it deletes a user, all follow relationships and all activities", %{user: u user_activities = user.ap_id - |> Activity.query_by_actor() + |> Activity.Queries.by_actor() |> Repo.all() |> Enum.map(fn act -> act.data["type"] end) From 5bfbad13ad4dd009b172748d81f56ead21c700de Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 3 Sep 2019 21:33:02 +0700 Subject: [PATCH 053/272] Add more tests for Pleroma.Activity --- test/activity_test.exs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/activity_test.exs b/test/activity_test.exs index 4152aaa7e..f9f789a76 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -185,4 +185,35 @@ test "all_by_ids_with_object/1" do assert [%{id: ^id1, object: %Object{}}, %{id: ^id2, object: %Object{}}] = activities end + + test "get_by_id_with_object/1" do + %{id: id} = insert(:note_activity) + + assert %Activity{id: ^id, object: %Object{}} = Activity.get_by_id_with_object(id) + end + + test "get_by_ap_id_with_object/1" do + %{data: %{"id" => ap_id}} = insert(:note_activity) + + assert %Activity{data: %{"id" => ^ap_id}, object: %Object{}} = + Activity.get_by_ap_id_with_object(ap_id) + end + + test "get_by_id/1" do + %{id: id} = insert(:note_activity) + + assert %Activity{id: ^id} = Activity.get_by_id(id) + end + + test "all_by_actor_and_id/2" do + user = insert(:user) + + {:ok, %{id: id1}} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofe"}) + {:ok, %{id: id2}} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofefe"}) + + assert [] == Activity.all_by_actor_and_id(user, []) + + assert [%Activity{id: ^id2}, %Activity{id: ^id1}] = + Activity.all_by_actor_and_id(user.ap_id, [id1, id2]) + end end From ce23529d917c1830b270a29e774e4ed7768bfeff Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 11:36:49 +0300 Subject: [PATCH 054/272] Use delivery info when federating deletes --- lib/pleroma/delivery.ex | 4 ++ lib/pleroma/user.ex | 4 ++ lib/pleroma/web/activity_pub/publisher.ex | 15 ++++- test/web/activity_pub/publisher_test.exs | 68 ++++++++++++++++++++++- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/delivery.ex b/lib/pleroma/delivery.ex index f9a9e35cd..2e7c019fa 100644 --- a/lib/pleroma/delivery.ex +++ b/lib/pleroma/delivery.ex @@ -46,6 +46,10 @@ def get_or_create(object_id, user_id) do end end + # A hack because user delete activities have a fake id for whatever reason + # TODO: Get rid of this + def delete_all_by_object_id("pleroma:fake_object_id"), do: {0, []} + def delete_all_by_object_id(object_id) do from(d in Delivery, where: d.object_id == ^object_id) |> Repo.delete_all() diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 9614acdab..785b22643 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1627,6 +1627,10 @@ def is_internal_user?(%User{nickname: nil}), do: true def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true def is_internal_user?(_), do: false + # A hack because user delete activities have a fake id for whatever reason + # TODO: Get rid of this + def get_delivered_users_by_object_id("pleroma:fake_object_id"), do: [] + def get_delivered_users_by_object_id(object_id) do from(u in User, inner_join: delivery in assoc(u, :deliveries), diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index c97405690..db64fd2f6 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -5,9 +5,11 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.Activity alias Pleroma.Config + alias Pleroma.Delivery alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.User + alias Pleroma.Object alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier @@ -107,7 +109,18 @@ defp recipients(actor, activity) do {:ok, []} end - Pleroma.Web.Salmon.remote_users(actor, activity) ++ followers + fetchers = + with %Activity{data: %{"type" => "Delete"}} <- activity, + %Object{id: object_id} <- Object.normalize(activity), + fetchers <- User.get_delivered_users_by_object_id(object_id), + _ <- Delivery.delete_all_by_object_id(object_id) do + fetchers + else + _ -> + [] + end + + Pleroma.Web.Salmon.remote_users(actor, activity) ++ followers ++ fetchers end defp get_cc_ap_ids(ap_id, recipients) do diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index 36a39c84c..32b7a242c 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -3,15 +3,17 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.PublisherTest do - use Pleroma.DataCase + use Pleroma.Web.ConnCase import Pleroma.Factory import Tesla.Mock import Mock alias Pleroma.Activity + alias Pleroma.Object alias Pleroma.Instances alias Pleroma.Web.ActivityPub.Publisher + alias Pleroma.Web.CommonAPI @as_public "https://www.w3.org/ns/activitystreams#Public" @@ -262,5 +264,69 @@ test "it returns inbox for messages involving single recipients in total" do }) ) end + + test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.", + Pleroma.Web.Federator.Publisher, + [:passthrough], + [] do + fetcher = + insert(:user, + local: false, + info: %{ + ap_enabled: true, + source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"} + } + ) + + another_fetcher = + insert(:user, + local: false, + info: %{ + ap_enabled: true, + source_data: %{"inbox" => "https://domain2.com/users/nick1/inbox"} + } + ) + + actor = insert(:user) + + note_activity = insert(:note_activity, user: actor) + object = Object.normalize(note_activity) + + activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url()) + object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) + + build_conn() + |> put_req_header("accept", "application/activity+json") + |> assign(:user, fetcher) + |> get(object_path) + |> json_response(200) + + build_conn() + |> put_req_header("accept", "application/activity+json") + |> assign(:user, another_fetcher) + |> get(activity_path) + |> json_response(200) + + {:ok, delete} = CommonAPI.delete(note_activity.id, actor) + + res = Publisher.publish(actor, delete) + assert res == :ok + + assert called( + Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ + inbox: "https://domain.com/users/nick1/inbox", + actor: actor, + id: delete.data["id"] + }) + ) + + assert called( + Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ + inbox: "https://domain2.com/users/nick1/inbox", + actor: actor, + id: delete.data["id"] + }) + ) + end end end From fb96facc32fb275efffeefa2892a1098ecd68b77 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 12:06:31 +0300 Subject: [PATCH 055/272] Remove unused functions and fix credo issues --- lib/pleroma/delivery.ex | 16 ++-------------- lib/pleroma/web/activity_pub/publisher.ex | 2 +- test/web/activity_pub/publisher_test.exs | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/lib/pleroma/delivery.ex b/lib/pleroma/delivery.ex index 2e7c019fa..ce8fb96f4 100644 --- a/lib/pleroma/delivery.ex +++ b/lib/pleroma/delivery.ex @@ -7,9 +7,9 @@ defmodule Pleroma.Delivery do alias Pleroma.Delivery alias Pleroma.FlakeId - alias Pleroma.User - alias Pleroma.Repo alias Pleroma.Object + alias Pleroma.Repo + alias Pleroma.User alias Pleroma.User import Ecto.Changeset @@ -39,13 +39,6 @@ def get(object_id, user_id) do |> Repo.one() end - def get_or_create(object_id, user_id) do - case get(object_id, user_id) do - %Delivery{} = delivery -> {:ok, delivery} - nil -> create(object_id, user_id) - end - end - # A hack because user delete activities have a fake id for whatever reason # TODO: Get rid of this def delete_all_by_object_id("pleroma:fake_object_id"), do: {0, []} @@ -54,9 +47,4 @@ def delete_all_by_object_id(object_id) do from(d in Delivery, where: d.object_id == ^object_id) |> Repo.delete_all() end - - def get_all_by_object_id(object_id) do - from(d in Delivery, where: d.object_id == ^object_id) - |> Repo.all() - end end diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index db64fd2f6..c39e89a6a 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -8,8 +8,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.Delivery alias Pleroma.HTTP alias Pleroma.Instances - alias Pleroma.User alias Pleroma.Object + alias Pleroma.User alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index 32b7a242c..0ef97464e 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -10,8 +10,8 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do import Mock alias Pleroma.Activity - alias Pleroma.Object alias Pleroma.Instances + alias Pleroma.Object alias Pleroma.Web.ActivityPub.Publisher alias Pleroma.Web.CommonAPI From 517017048316a52172d60d26b03beddb85af7b39 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 10:09:46 +0000 Subject: [PATCH 056/272] Apply suggestion to lib/pleroma/web/activity_pub/activity_pub_controller.ex --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 009260d3f..025641722 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -26,10 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do plug( Pleroma.Plugs.Cache, - [ - query_params: false, - tracking_fun: &Pleroma.Web.ActivityPub.ActivityPubController.track_object_fetch/2 - ] + [query_params: false, tracking_fun: &__MODULE__.track_object_fetch/2] when action in [:activity, :object] ) From 3896a51b8aefe6fe54251ffd559c636980faa87e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 10:09:56 +0000 Subject: [PATCH 057/272] Apply suggestion to lib/pleroma/web/activity_pub/activity_pub_controller.ex --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 025641722..4bd13defb 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -72,9 +72,8 @@ def object(conn, %{"uuid" => uuid}) do end def track_object_fetch(conn, object_id) do - case conn.assigns[:user] do - %User{id: user_id} -> Delivery.create(object_id, user_id) - _ -> nil + with %{assigns: %{user: %User{id: user_id}}} <- conn do + Delivery.create(object_id, user_id) end conn From ec5aaf5bd72c91db93a9dbfbe73b58cf7ae5e566 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 13 Sep 2019 14:59:58 +0300 Subject: [PATCH 058/272] fix tests --- .../mastodon_api/mastodon_api_controller_test.exs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 35c2236c8..f899d77d9 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3626,16 +3626,16 @@ test "returns bad_request if missing required params", %{ res = post(conn, "/api/v1/accounts", valid_params) assert json_response(res, 200) - Enum.each(valid_params, fn {attr, _} -> + [{127,0,0,1}, {127,0,0,2}, {127,0,0,3}, {127,0,0,4}] + |> Stream.zip(valid_params) + |> Enum.each(fn {ip, {attr, _}} -> res = conn - |> Map.put( - :remote_ip, - {:rand.uniform(15), :rand.uniform(15), :rand.uniform(15), :rand.uniform(15)} - ) + |> Map.put(:remote_ip, ip) |> post("/api/v1/accounts", Map.delete(valid_params, attr)) + |> json_response(400) - assert json_response(res, 400) == %{"error" => "Missing parameters"} + assert res == %{"error" => "Missing parameters"} end) end From bc3e8c033bbef303890ff6afa92d1fe365e530fb Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 13 Sep 2019 15:06:34 +0300 Subject: [PATCH 059/272] fix formatting --- test/web/mastodon_api/mastodon_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f899d77d9..58efbba38 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3626,7 +3626,7 @@ test "returns bad_request if missing required params", %{ res = post(conn, "/api/v1/accounts", valid_params) assert json_response(res, 200) - [{127,0,0,1}, {127,0,0,2}, {127,0,0,3}, {127,0,0,4}] + [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}] |> Stream.zip(valid_params) |> Enum.each(fn {ip, {attr, _}} -> res = From 2784962dba295ee35677e93996df53d1711e5768 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 15:23:03 +0000 Subject: [PATCH 060/272] Apply suggestion to lib/pleroma/web/activity_pub/activity_pub_controller.ex --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 4bd13defb..70d4a5baf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -130,7 +130,7 @@ defp maybe_set_tracking_data(conn, %Activity{data: %{"type" => "Create"}} = acti assign(conn, :tracking_fun_data, object_id) end - defp maybe_set_tracking_data(conn, _activity), do: assign(conn, :tracking_fun_data, nil) + defp maybe_set_tracking_data(conn, _activity), do: conn defp set_cache_ttl_for(conn, %Activity{object: object}) do set_cache_ttl_for(conn, object) From 05f8a066a107af2f7151aee8d85af97cf6a4835c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 15:23:26 +0000 Subject: [PATCH 061/272] Apply suggestion to lib/pleroma/delivery.ex --- lib/pleroma/delivery.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/delivery.ex b/lib/pleroma/delivery.ex index ce8fb96f4..38c148c34 100644 --- a/lib/pleroma/delivery.ex +++ b/lib/pleroma/delivery.ex @@ -31,7 +31,7 @@ def changeset(delivery, params \\ %{}) do def create(object_id, user_id) do %Delivery{} |> changeset(%{user_id: user_id, object_id: object_id}) - |> Repo.insert() + |> Repo.insert(on_conflict: :nothing) end def get(object_id, user_id) do From 8900cb68aef535dbf60de87fce47d85b91909077 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 15:25:15 +0000 Subject: [PATCH 062/272] Apply suggestion to lib/pleroma/web/activity_pub/activity_pub_controller.ex --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 70d4a5baf..01b34fb1d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -71,6 +71,8 @@ def object(conn, %{"uuid" => uuid}) do end end + def track_object_fetch(conn, nil), do: conn + def track_object_fetch(conn, object_id) do with %{assigns: %{user: %User{id: user_id}}} <- conn do Delivery.create(object_id, user_id) From 0bd2b85edbf3b7062570778649cf2b77cc7a0bce Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 13 Sep 2019 18:25:27 +0300 Subject: [PATCH 063/272] Separate Subscription Notifications from regular Notifications --- lib/pleroma/notification.ex | 1 - lib/pleroma/subscription_notification.ex | 266 ++++++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 2 + .../controllers/mastodon_api_controller.ex | 48 ++++ lib/pleroma/web/mastodon_api/mastodon_api.ex | 10 + .../views/subscription_notification_view.ex | 61 ++++ .../web/pleroma_api/pleroma_api_controller.ex | 26 ++ lib/pleroma/web/push/impl.ex | 3 +- lib/pleroma/web/router.ex | 28 ++ lib/pleroma/web/streamer.ex | 14 +- ...5028_create_subscription_notifications.exs | 15 + test/notification_test.exs | 12 +- .../mastodon_api_controller_test.exs | 192 +++++++++++++ test/web/mastodon_api/mastodon_api_test.exs | 4 +- 14 files changed, 670 insertions(+), 12 deletions(-) create mode 100644 lib/pleroma/subscription_notification.ex create mode 100644 lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex create mode 100644 priv/repo/migrations/20190824195028_create_subscription_notifications.exs diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index b7c880c51..716d98733 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -228,7 +228,6 @@ def get_notified_from_activity( [] |> Utils.maybe_notify_to_recipients(activity) |> Utils.maybe_notify_mentioned_recipients(activity) - |> Utils.maybe_notify_subscribers(activity) |> Enum.uniq() User.get_users_from_set(recipients, local_only) diff --git a/lib/pleroma/subscription_notification.ex b/lib/pleroma/subscription_notification.ex new file mode 100644 index 000000000..7ae25a7b1 --- /dev/null +++ b/lib/pleroma/subscription_notification.ex @@ -0,0 +1,266 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.SubscriptionNotification do + use Ecto.Schema + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Pagination + alias Pleroma.Repo + alias Pleroma.SubscriptionNotification + alias Pleroma.User + alias Pleroma.Web.CommonAPI.Utils + alias Pleroma.Web.Push + alias Pleroma.Web.Streamer + + import Ecto.Query + import Ecto.Changeset + + @type t :: %__MODULE__{} + + schema "subscription_notifications" do + belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:activity, Activity, type: Pleroma.FlakeId) + + timestamps() + end + + def changeset(%SubscriptionNotification{} = notification, attrs) do + cast(notification, attrs, []) + end + + def for_user_query(user, opts \\ []) do + query = + SubscriptionNotification + |> where(user_id: ^user.id) + |> where( + [n, a], + fragment( + "? not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')", + a.actor + ) + ) + |> join(:inner, [n], activity in assoc(n, :activity)) + |> join(:left, [n, a], object in Object, + on: + fragment( + "(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)", + object.data, + a.data + ) + ) + |> preload([n, a, o], activity: {a, object: o}) + + if opts[:with_muted] do + query + else + where(query, [n, a], a.actor not in ^user.info.muted_notifications) + |> where([n, a], a.actor not in ^user.info.blocks) + |> where( + [n, a], + fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks + ) + |> join(:left, [n, a], tm in Pleroma.ThreadMute, + on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data) + ) + |> where([n, a, o, tm], is_nil(tm.user_id)) + end + end + + def for_user(user, opts \\ %{}) do + user + |> for_user_query(opts) + |> Pagination.fetch_paginated(opts) + end + + @doc """ + Returns notifications for user received since given date. + + ## Examples + + iex> Pleroma.SubscriptionNotification.for_user_since(%Pleroma.User{}, ~N[2019-04-13 11:22:33]) + [%Pleroma.SubscriptionNotification{}, %Pleroma.SubscriptionNotification{}] + + iex> Pleroma.SubscriptionNotification.for_user_since(%Pleroma.User{}, ~N[2019-04-15 11:22:33]) + [] + """ + @spec for_user_since(Pleroma.User.t(), NaiveDateTime.t()) :: [t()] + def for_user_since(user, date) do + from(n in for_user_query(user), + where: n.updated_at > ^date + ) + |> Repo.all() + end + + def clear_up_to(%{id: user_id} = _user, id) do + from( + n in SubscriptionNotification, + where: n.user_id == ^user_id, + where: n.id <= ^id + ) + |> Repo.delete_all([]) + end + + def get(%{id: user_id} = _user, id) do + query = + from( + n in SubscriptionNotification, + where: n.id == ^id, + join: activity in assoc(n, :activity), + preload: [activity: activity] + ) + + notification = Repo.one(query) + + case notification do + %{user_id: ^user_id} -> + {:ok, notification} + + _ -> + {:error, "Cannot get notification"} + end + end + + def clear(user) do + from(n in SubscriptionNotification, where: n.user_id == ^user.id) + |> Repo.delete_all() + end + + def destroy_multiple(%{id: user_id} = _user, ids) do + from(n in SubscriptionNotification, + where: n.id in ^ids, + where: n.user_id == ^user_id + ) + |> Repo.delete_all() + end + + def dismiss(%{id: user_id} = _user, id) do + notification = Repo.get(SubscriptionNotification, id) + + case notification do + %{user_id: ^user_id} -> + Repo.delete(notification) + + _ -> + {:error, "Cannot dismiss notification"} + end + end + + def create_notifications(%Activity{data: %{"to" => _, "type" => "Create"}} = activity) do + object = Object.normalize(activity) + + unless object && object.data["type"] == "Answer" do + users = get_notified_from_activity(activity) + notifications = Enum.map(users, fn user -> create_notification(activity, user) end) + {:ok, notifications} + else + {:ok, []} + end + end + + def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity) + when type in ["Like", "Announce", "Follow"] do + users = get_notified_from_activity(activity) + notifications = Enum.map(users, fn user -> create_notification(activity, user) end) + {:ok, notifications} + end + + def create_notifications(_), do: {:ok, []} + + # TODO move to sql, too. + def create_notification(%Activity{} = activity, %User{} = user) do + unless skip?(activity, user) do + notification = %SubscriptionNotification{user_id: user.id, activity: activity} + {:ok, notification} = Repo.insert(notification) + Streamer.stream("user", notification) + Streamer.stream("user:subscription_notification", notification) + Push.send(notification) + notification + end + end + + def get_notified_from_activity(activity, local_only \\ true) + + def get_notified_from_activity( + %Activity{data: %{"to" => _, "type" => type} = _data} = activity, + local_only + ) + when type in ["Create", "Like", "Announce", "Follow"] do + recipients = + [] + |> Utils.maybe_notify_subscribers(activity) + |> Enum.uniq() + + User.get_users_from_set(recipients, local_only) + end + + def get_notified_from_activity(_, _local_only), do: [] + + @spec skip?(Activity.t(), User.t()) :: boolean() + def skip?(activity, user) do + [ + :self, + :followers, + :follows, + :non_followers, + :non_follows, + :recently_followed + ] + |> Enum.any?(&skip?(&1, activity, user)) + end + + @spec skip?(atom(), Activity.t(), User.t()) :: boolean() + def skip?(:self, activity, user) do + activity.data["actor"] == user.ap_id + end + + def skip?( + :followers, + activity, + %{info: %{notification_settings: %{"followers" => false}}} = user + ) do + actor = activity.data["actor"] + follower = User.get_cached_by_ap_id(actor) + User.following?(follower, user) + end + + def skip?( + :non_followers, + activity, + %{info: %{notification_settings: %{"non_followers" => false}}} = user + ) do + actor = activity.data["actor"] + follower = User.get_cached_by_ap_id(actor) + !User.following?(follower, user) + end + + def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do + actor = activity.data["actor"] + followed = User.get_cached_by_ap_id(actor) + User.following?(user, followed) + end + + def skip?( + :non_follows, + activity, + %{info: %{notification_settings: %{"non_follows" => false}}} = user + ) do + actor = activity.data["actor"] + followed = User.get_cached_by_ap_id(actor) + !User.following?(user, followed) + end + + def skip?(:recently_followed, %{data: %{"type" => "Follow"}} = activity, user) do + actor = activity.data["actor"] + + SubscriptionNotification.for_user(user) + |> Enum.any?(fn + %{activity: %{data: %{"type" => "Follow", "actor" => ^actor}}} -> true + _ -> false + end) + end + + def skip?(_, _, _), do: false +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index d23ec66ac..bc9a7a2d6 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Object.Fetcher alias Pleroma.Pagination alias Pleroma.Repo + alias Pleroma.SubscriptionNotification alias Pleroma.Upload alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF @@ -148,6 +149,7 @@ def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when PleromaJobQueue.enqueue(:background, Pleroma.Web.RichMedia.Helpers, [:fetch, activity]) Notification.create_notifications(activity) + SubscriptionNotification.create_notifications(activity) participations = activity diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index c54462bb3..3730c962c 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.Stats + alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.ActivityPub.ActivityPub @@ -39,6 +40,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.ReportView alias Pleroma.Web.MastodonAPI.ScheduledActivityView alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.MastodonAPI.SubscriptionNotificationView alias Pleroma.Web.MediaProxy alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization @@ -725,6 +727,28 @@ def notifications(%{assigns: %{user: user}} = conn, params) do |> render("index.json", %{notifications: notifications, for: user}) end + def subscription_notifications(%{assigns: %{user: user}} = conn, params) do + notifications = MastodonAPI.get_subscription_notifications(user, params) + + conn + |> add_link_headers(:subscription_notifications, notifications) + |> put_view(SubscriptionNotificationView) + |> render("index.json", %{notifications: notifications, for: user}) + end + + def get_subscription_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do + with {:ok, notification} <- SubscriptionNotification.get(user, id) do + conn + |> put_view(SubscriptionNotificationView) + |> render("show.json", %{subscription_notification: notification, for: user}) + else + {:error, reason} -> + conn + |> put_status(:forbidden) + |> json(%{"error" => reason}) + end + end + def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do with {:ok, notification} <- Notification.get(user, id) do conn @@ -743,6 +767,11 @@ def clear_notifications(%{assigns: %{user: user}} = conn, _params) do json(conn, %{}) end + def clear_subscription_notifications(%{assigns: %{user: user}} = conn, _params) do + SubscriptionNotification.clear(user) + json(conn, %{}) + end + def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do with {:ok, _notif} <- Notification.dismiss(user, id) do json(conn, %{}) @@ -754,11 +783,30 @@ def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _para end end + def dismiss_subscription_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do + with {:ok, _notif} <- SubscriptionNotification.dismiss(user, id) do + json(conn, %{}) + else + {:error, reason} -> + conn + |> put_status(:forbidden) + |> json(%{"error" => reason}) + end + end + def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do Notification.destroy_multiple(user, ids) json(conn, %{}) end + def destroy_multiple_subscription_notifications( + %{assigns: %{user: user}} = conn, + %{"ids" => ids} = _params + ) do + SubscriptionNotification.destroy_multiple(user, ids) + json(conn, %{}) + end + def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do id = List.wrap(id) q = from(u in User, where: u.id in ^id) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index ac01d1ff3..6751e24d8 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do alias Pleroma.Notification alias Pleroma.Pagination alias Pleroma.ScheduledActivity + alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -62,6 +63,15 @@ def get_notifications(user, params \\ %{}) do |> Pagination.fetch_paginated(params) end + def get_subscription_notifications(user, params \\ %{}) do + options = cast_params(params) + + user + |> SubscriptionNotification.for_user_query(options) + |> restrict(:exclude_types, options) + |> Pagination.fetch_paginated(params) + end + def get_scheduled_activities(user, params \\ %{}) do user |> ScheduledActivity.for_user_query() diff --git a/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex b/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex new file mode 100644 index 000000000..c6f0b5064 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex @@ -0,0 +1,61 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.SubscriptionNotificationView do + use Pleroma.Web, :view + + alias Pleroma.Activity + # alias Pleroma.SubscriptionNotification + alias Pleroma.User + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.AccountView + alias Pleroma.Web.MastodonAPI.SubscriptionNotificationView + alias Pleroma.Web.MastodonAPI.StatusView + + def render("index.json", %{notifications: notifications, for: user}) do + safe_render_many(notifications, SubscriptionNotificationView, "show.json", %{for: user}) + end + + def render("show.json", %{ + subscription_notification: %{activity: activity} = notification, + for: user + }) do + actor = User.get_cached_by_ap_id(activity.data["actor"]) + parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"]) + mastodon_type = Activity.mastodon_notification_type(activity) + + response = %{ + id: to_string(notification.id), + type: mastodon_type, + created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at), + account: AccountView.render("account.json", %{user: actor, for: user}) + } + + case mastodon_type do + "mention" -> + response + |> Map.merge(%{ + status: StatusView.render("status.json", %{activity: activity, for: user}) + }) + + "favourite" -> + response + |> Map.merge(%{ + status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + }) + + "reblog" -> + response + |> Map.merge(%{ + status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + }) + + "follow" -> + response + + _ -> + nil + end + end +end diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index f4df3b024..71792d913 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do alias Pleroma.Conversation.Participation alias Pleroma.Notification + alias Pleroma.SubscriptionNotification alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.NotificationView @@ -95,4 +96,29 @@ def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) d |> render("index.json", %{notifications: notifications, for: user}) end end + + def delete_subscription_notification(%{assigns: %{user: user}} = conn, %{ + "id" => notification_id + }) do + with {:ok, notification} <- SubscriptionNotification.dismiss(user, notification_id) do + conn + |> put_view(NotificationView) + |> render("show.json", %{notification: notification, for: user}) + else + {:error, message} -> + conn + |> put_status(:bad_request) + |> json(%{"error" => message}) + end + end + + def read_subscription_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do + with notifications <- SubscriptionNotification.clear_up_to(user, max_id) do + notifications = Enum.take(notifications, 80) + + conn + |> put_view(NotificationView) + |> render("index.json", %{notifications: notifications, for: user}) + end + end end diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index 35d3ff07c..7ea5607fa 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.Push.Impl do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web.Metadata.Utils alias Pleroma.Web.Push.Subscription @@ -19,7 +20,7 @@ defmodule Pleroma.Web.Push.Impl do @types ["Create", "Follow", "Announce", "Like"] @doc "Performs sending notifications for user subscriptions" - @spec perform(Notification.t()) :: list(any) | :error + @spec perform(Notification.t() | SubscriptionNotification.t()) :: list(any) | :error def perform( %{ activity: %{data: %{"type" => activity_type}, id: activity_id} = activity, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b0464037e..dbd0deecd 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -300,11 +300,39 @@ defmodule Pleroma.Web.Router do get("/bookmarks", MastodonAPIController, :bookmarks) post("/notifications/clear", MastodonAPIController, :clear_notifications) + + post( + "/notifications/subscription/clear", + MastodonAPIController, + :clear_subscription_notifications + ) + post("/notifications/dismiss", MastodonAPIController, :dismiss_notification) + + post( + "/notifications/subscription/dismiss", + MastodonAPIController, + :dismiss_subscription_notification + ) + get("/notifications", MastodonAPIController, :notifications) + get("/notifications/subscription", MastodonAPIController, :subscription_notifications) get("/notifications/:id", MastodonAPIController, :get_notification) + + get( + "/notifications/subscription/:id", + MastodonAPIController, + :get_subscription_notification + ) + delete("/notifications/destroy_multiple", MastodonAPIController, :destroy_multiple) + delete( + "/notifications/subscription/destroy_multiple", + MastodonAPIController, + :destroy_multiple_subscription_notifications + ) + get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses) get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 587c43f40..42d95e33a 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.Streamer do alias Pleroma.Conversation.Participation alias Pleroma.Notification alias Pleroma.Object + alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Visibility @@ -208,10 +209,17 @@ def represent_conversation(%Participation{} = participation) do |> Jason.encode!() end - @spec represent_notification(User.t(), Notification.t()) :: binary() - defp represent_notification(%User{} = user, %Notification{} = notify) do + @spec represent_notification(User.t(), Notification.t() | %SubscriptionNotification{}) :: + binary() + defp represent_notification(%User{} = user, notify) do + event = + case notify do + %Notification{} -> "notification" + %SubscriptionNotification{} -> "subscription_norification" + end + %{ - event: "notification", + event: event, payload: NotificationView.render( "show.json", diff --git a/priv/repo/migrations/20190824195028_create_subscription_notifications.exs b/priv/repo/migrations/20190824195028_create_subscription_notifications.exs new file mode 100644 index 000000000..fcceb4386 --- /dev/null +++ b/priv/repo/migrations/20190824195028_create_subscription_notifications.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.CreateSubscriptionNotifications do + use Ecto.Migration + + def change do + create_if_not_exists table(:subscription_notifications) do + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:activity_id, references(:activities, type: :uuid, on_delete: :delete_all)) + + timestamps() + end + + create_if_not_exists(index(:subscription_notifications, [:user_id])) + create_if_not_exists(index(:subscription_notifications, ["id desc nulls last"])) + end +end diff --git a/test/notification_test.exs b/test/notification_test.exs index 2a52dad8d..0e2635aad 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -32,16 +32,16 @@ test "notifies someone when they are directly addressed" do assert other_notification.activity_id == activity.id end - test "it creates a notification for subscribed users" do + test "it does not create a notification for subscribed users" do user = insert(:user) subscriber = insert(:user) User.subscribe(subscriber, user) {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"}) - {:ok, [notification]} = Notification.create_notifications(status) + {:ok, notifications} = Notification.create_notifications(status) - assert notification.user_id == subscriber.id + assert notifications == [] end test "does not create a notification for subscribed users if status is a reply" do @@ -190,14 +190,16 @@ test "it doesn't create a notification for follow-unfollow-follow chains" do refute Notification.create_notification(activity_dupe, followed_user) end - test "it doesn't create duplicate notifications for follow+subscribed users" do + test "it doesn't create notifications for follow+subscribed users" do user = insert(:user) subscriber = insert(:user) {:ok, _, _, _} = CommonAPI.follow(subscriber, user) User.subscribe(subscriber, user) {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"}) - {:ok, [_notif]} = Notification.create_notifications(status) + {:ok, notifications} = Notification.create_notifications(status) + + assert notifications == [] end test "it doesn't create subscription notifications if the recipient cannot see the status" do diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f4902d043..95fcecc52 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -13,6 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Pleroma.Object alias Pleroma.Repo alias Pleroma.ScheduledActivity + alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI @@ -1273,6 +1274,197 @@ test "see notifications after muting user with notifications and with_muted para end end + describe "subscription_notifications" do + setup do + user = insert(:user) + subscriber = insert(:user) + + User.subscribe(subscriber, user) + + {:ok, %{user: user, subscriber: subscriber}} + end + + test "list of notifications", %{conn: conn, user: user, subscriber: subscriber} do + status_text = "Hello" + {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) + + conn = + conn + |> assign(:user, subscriber) + |> get("/api/v1/notifications/subscription") + + assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) + assert response == status_text + end + + test "getting a single notification", %{conn: conn, user: user, subscriber: subscriber} do + status_text = "Hello" + + {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) + [notification] = Repo.all(SubscriptionNotification) + + conn = + conn + |> assign(:user, subscriber) + |> get("/api/v1/notifications/subscription/#{notification.id}") + + assert %{"status" => %{"content" => response}} = json_response(conn, 200) + assert response == status_text + end + + test "dismissing a single notification also deletes it", %{ + conn: conn, + user: user, + subscriber: subscriber + } do + status_text = "Hello" + {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) + + [notification] = Repo.all(SubscriptionNotification) + + conn = + conn + |> assign(:user, subscriber) + |> post("/api/v1/notifications/subscription/dismiss", %{"id" => notification.id}) + + assert %{} = json_response(conn, 200) + + assert Repo.all(SubscriptionNotification) == [] + end + + test "clearing all notifications also deletes them", %{ + conn: conn, + user: user, + subscriber: subscriber + } do + status_text1 = "Hello" + status_text2 = "Hello again" + {:ok, _activity1} = CommonAPI.post(user, %{"status" => status_text1}) + {:ok, _activity2} = CommonAPI.post(user, %{"status" => status_text2}) + + conn = + conn + |> assign(:user, subscriber) + |> post("/api/v1/notifications/subscription/clear") + + assert %{} = json_response(conn, 200) + + conn = + build_conn() + |> assign(:user, subscriber) + |> get("/api/v1/notifications/subscription") + + assert json_response(conn, 200) == [] + + assert Repo.all(SubscriptionNotification) == [] + end + + test "paginates notifications using min_id, since_id, max_id, and limit", %{ + conn: conn, + user: user, + subscriber: subscriber + } do + {:ok, activity1} = CommonAPI.post(user, %{"status" => "Hello 1"}) + {:ok, activity2} = CommonAPI.post(user, %{"status" => "Hello 2"}) + {:ok, activity3} = CommonAPI.post(user, %{"status" => "Hello 3"}) + {:ok, activity4} = CommonAPI.post(user, %{"status" => "Hello 4"}) + + notification1_id = + Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() + + notification2_id = + Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() + + notification3_id = + Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() + + notification4_id = + Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() + + conn = assign(conn, :user, subscriber) + + # min_id + conn_res = + get(conn, "/api/v1/notifications/subscription?limit=2&min_id=#{notification1_id}") + + result = json_response(conn_res, 200) + assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + + # since_id + conn_res = + get(conn, "/api/v1/notifications/subscription?limit=2&since_id=#{notification1_id}") + + result = json_response(conn_res, 200) + assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + + # max_id + conn_res = + get(conn, "/api/v1/notifications/subscription?limit=2&max_id=#{notification4_id}") + + result = json_response(conn_res, 200) + assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + end + + test "destroy multiple", %{conn: conn, user: user1, subscriber: user2} do + # mutual subscription + User.subscribe(user1, user2) + + {:ok, activity1} = CommonAPI.post(user1, %{"status" => "Hello 1"}) + {:ok, activity2} = CommonAPI.post(user1, %{"status" => "World 1"}) + {:ok, activity3} = CommonAPI.post(user2, %{"status" => "Hello 2"}) + {:ok, activity4} = CommonAPI.post(user2, %{"status" => "World 2"}) + + notification1_id = + Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() + + notification2_id = + Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() + + notification3_id = + Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() + + notification4_id = + Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() + + conn = assign(conn, :user, user1) + + conn_res = get(conn, "/api/v1/notifications/subscription") + + result = json_response(conn_res, 200) + + Enum.each(result, fn %{"id" => id} -> + assert id in [notification3_id, notification4_id] + end) + + conn2 = assign(conn, :user, user2) + + conn_res = get(conn2, "/api/v1/notifications/subscription") + + result = json_response(conn_res, 200) + + Enum.each(result, fn %{"id" => id} -> + assert id in [notification1_id, notification2_id] + end) + + conn_destroy = + delete(conn, "/api/v1/notifications/subscription/destroy_multiple", %{ + "ids" => [notification3_id, notification4_id] + }) + + assert json_response(conn_destroy, 200) == %{} + + conn_res = get(conn2, "/api/v1/notifications/subscription") + + result = json_response(conn_res, 200) + + Enum.each(result, fn %{"id" => id} -> + assert id in [notification1_id, notification2_id] + end) + + assert length(Repo.all(SubscriptionNotification)) == 2 + end + end + describe "reblogging" do test "reblogs and returns the reblogged status", %{conn: conn} do activity = insert(:note_activity) diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/web/mastodon_api/mastodon_api_test.exs index 7fcb2bd55..848fce7ad 100644 --- a/test/web/mastodon_api/mastodon_api_test.exs +++ b/test/web/mastodon_api/mastodon_api_test.exs @@ -75,9 +75,9 @@ test "returns notifications for user" do User.subscribe(subscriber, user) - {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"}) + {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin @#{subscriber.nickname}"}) - {:ok, status1} = CommonAPI.post(user, %{"status" => "Magi"}) + {:ok, status1} = CommonAPI.post(user, %{"status" => "Magi @#{subscriber.nickname}"}) {:ok, [notification]} = Notification.create_notifications(status) {:ok, [notification1]} = Notification.create_notifications(status1) res = MastodonAPI.get_notifications(subscriber) From 25a64a4aa0a10bf06c2ccdf9a6c493f184170a89 Mon Sep 17 00:00:00 2001 From: stwf Date: Fri, 13 Sep 2019 11:46:41 -0400 Subject: [PATCH 064/272] Capture test error messages where appropriate --- test/integration/mastodon_websocket_test.exs | 29 ++++++++++++++----- test/web/activity_pub/publisher_test.exs | 24 +++++++++------ test/web/activity_pub/relay_test.exs | 13 +++++++-- .../mastodon_api_controller_test.exs | 14 +++++---- test/web/twitter_api/util_controller_test.exs | 13 +++++---- .../web_finger/web_finger_controller_test.exs | 13 +++++---- 6 files changed, 70 insertions(+), 36 deletions(-) diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index 3975cdcd6..63bf73412 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do use Pleroma.DataCase + import ExUnit.CaptureLog import Pleroma.Factory alias Pleroma.Integration.WebsocketClient @@ -39,13 +40,17 @@ def start_socket(qs \\ nil, headers \\ []) do end test "refuses invalid requests" do - assert {:error, {400, _}} = start_socket() - assert {:error, {404, _}} = start_socket("?stream=ncjdk") + capture_log(fn -> + assert {:error, {400, _}} = start_socket() + assert {:error, {404, _}} = start_socket("?stream=ncjdk") + end) end test "requires authentication and a valid token for protected streams" do - assert {:error, {403, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa") - assert {:error, {403, _}} = start_socket("?stream=user") + capture_log(fn -> + assert {:error, {403, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa") + assert {:error, {403, _}} = start_socket("?stream=user") + end) end test "allows public streams without authentication" do @@ -100,19 +105,27 @@ test "accepts valid tokens", state do test "accepts the 'user' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") - assert {:error, {403, "Forbidden"}} = start_socket("?stream=user") + + assert capture_log(fn -> + assert {:error, {403, "Forbidden"}} = start_socket("?stream=user") + end) =~ ":badarg" end test "accepts the 'user:notification' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") - assert {:error, {403, "Forbidden"}} = start_socket("?stream=user:notification") + + assert capture_log(fn -> + assert {:error, {403, "Forbidden"}} = start_socket("?stream=user:notification") + end) =~ ":badarg" end test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}]) - assert {:error, {403, "Forbidden"}} = - start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}]) + assert capture_log(fn -> + assert {:error, {403, "Forbidden"}} = + start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}]) + end) =~ ":badarg" end end end diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index 36a39c84c..381757e1b 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do use Pleroma.DataCase + import ExUnit.CaptureLog import Pleroma.Factory import Tesla.Mock import Mock @@ -188,7 +189,10 @@ test "it returns inbox for messages involving single recipients in total" do actor = insert(:user) inbox = "http://connrefused.site/users/nick1/inbox" - assert {:error, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) + assert capture_log(fn -> + assert {:error, _} = + Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) + end) =~ "connrefused" assert called(Instances.set_unreachable(inbox)) end @@ -212,14 +216,16 @@ test "it returns inbox for messages involving single recipients in total" do actor = insert(:user) inbox = "http://connrefused.site/users/nick1/inbox" - assert {:error, _} = - Publisher.publish_one(%{ - inbox: inbox, - json: "{}", - actor: actor, - id: 1, - unreachable_since: NaiveDateTime.utc_now() - }) + assert capture_log(fn -> + assert {:error, _} = + Publisher.publish_one(%{ + inbox: inbox, + json: "{}", + actor: actor, + id: 1, + unreachable_since: NaiveDateTime.utc_now() + }) + end) =~ "connrefused" refute called(Instances.set_unreachable(inbox)) end diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 4f7d592a6..9db4255d8 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay + import ExUnit.CaptureLog import Pleroma.Factory import Mock @@ -20,7 +21,9 @@ test "gets an actor for the relay" do describe "follow/1" do test "returns errors when user not found" do - assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"} + assert capture_log(fn -> + assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"} + end) =~ "Could not fetch by AP id" end test "returns activity" do @@ -37,7 +40,9 @@ test "returns activity" do describe "unfollow/1" do test "returns errors when user not found" do - assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"} + assert capture_log(fn -> + assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"} + end) =~ "Could not fetch by AP id" end test "returns activity" do @@ -78,7 +83,9 @@ test "returns error when object is unknown" do } ) - assert Relay.publish(activity) == {:error, nil} + assert capture_log(fn -> + assert Relay.publish(activity) == {:error, nil} + end) =~ "[error] error: nil" end test_with_mock "returns announce activity and publish to federate", diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f4902d043..806ae7e69 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3963,13 +3963,15 @@ test "returns error", %{conn: conn, user: user} do Config.put([:suggestions, :enabled], true) Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}") - res = - conn - |> assign(:user, user) - |> get("/api/v1/suggestions") - |> json_response(500) + assert capture_log(fn -> + res = + conn + |> assign(:user, user) + |> get("/api/v1/suggestions") + |> json_response(500) - assert res == "Something went wrong" + assert res == "Something went wrong" + end) =~ "Could not retrieve suggestions" end test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index cf8e69d2b..e36d3130f 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI + import ExUnit.CaptureLog import Pleroma.Factory import Mock @@ -338,12 +339,14 @@ test "show follow page if the `acct` is a account link", %{conn: conn} do test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do user = insert(:user) - response = - conn - |> assign(:user, user) - |> get("/ostatus_subscribe?acct=https://mastodon.social/users/not_found") + assert capture_log(fn -> + response = + conn + |> assign(:user, user) + |> get("/ostatus_subscribe?acct=https://mastodon.social/users/not_found") - assert html_response(response, 200) =~ "Error fetching user" + assert html_response(response, 200) =~ "Error fetching user" + end) =~ "Object has been deleted" end end diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/web/web_finger/web_finger_controller_test.exs index e23086b2a..bd3ccaaf7 100644 --- a/test/web/web_finger/web_finger_controller_test.exs +++ b/test/web/web_finger/web_finger_controller_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do use Pleroma.Web.ConnCase + import ExUnit.CaptureLog import Pleroma.Factory import Tesla.Mock @@ -75,11 +76,13 @@ test "it returns 404 when user isn't found (XML)" do test "Sends a 404 when invalid format" do user = insert(:user) - assert_raise Phoenix.NotAcceptableError, fn -> - build_conn() - |> put_req_header("accept", "text/html") - |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") - end + assert capture_log(fn -> + assert_raise Phoenix.NotAcceptableError, fn -> + build_conn() + |> put_req_header("accept", "text/html") + |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") + end + end) =~ "no supported media type in accept header" end test "Sends a 400 when resource param is missing" do From 69faec031d62f4e87a1791ae0c71ca4b0f02f12b Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 13 Sep 2019 19:02:42 +0300 Subject: [PATCH 065/272] markdown generation to the new file --- lib/pleroma/docs/markdown.ex | 4 ++-- mix.exs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index 24930cc9f..8386dc2fb 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -3,9 +3,9 @@ defmodule Pleroma.Docs.Markdown do @spec process(keyword()) :: {:ok, String.t()} def process(descriptions) do - config_path = "docs/config.md" + config_path = "docs/generated_config.md" {:ok, file} = File.open(config_path, [:utf8, :write]) - IO.write(file, "# Configuration\n") + IO.write(file, "# Generated configuration\n") IO.write(file, "Date of generation: #{Date.utc_today()}\n\n") IO.write( diff --git a/mix.exs b/mix.exs index 96ef723b2..dfa530358 100644 --- a/mix.exs +++ b/mix.exs @@ -172,8 +172,7 @@ defp aliases do "ecto.rollback": ["pleroma.ecto.rollback"], "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], "ecto.reset": ["ecto.drop", "ecto.setup"], - test: ["ecto.create --quiet", "ecto.migrate", "test"], - docs: ["pleroma.docs", "docs"] + test: ["ecto.create --quiet", "ecto.migrate", "test"] ] end From c625fe6f09a308f10e98c9e5ea4bf14500a0b58a Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 13 Sep 2019 19:03:39 +0300 Subject: [PATCH 066/272] config.md back --- docs/config.md | 702 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 701 insertions(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index 7f54a34b1..066547bb1 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1 +1,701 @@ -This file is a placeholder, please run mix pleroma.docs to generate it. +# Configuration + +This file describe the configuration, it is recommended to edit the relevant *.secret.exs file instead of the others founds in the ``config`` directory. +If you run Pleroma with ``MIX_ENV=prod`` the file is ``prod.secret.exs``, otherwise it is ``dev.secret.exs``. + +## Pleroma.Upload +* `uploader`: Select which `Pleroma.Uploaders` to use +* `filters`: List of `Pleroma.Upload.Filter` to use. +* `link_name`: When enabled Pleroma will add a `name` parameter to the url of the upload, for example `https://instance.tld/media/corndog.png?name=corndog.png`. This is needed to provide the correct filename in Content-Disposition headers when using filters like `Pleroma.Upload.Filter.Dedupe` +* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host. +* `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it. +* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation. + +Note: `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`. + +## Pleroma.Uploaders.Local +* `uploads`: Which directory to store the user-uploads in, relative to pleroma’s working directory + +## Pleroma.Uploaders.S3 +* `bucket`: S3 bucket name +* `bucket_namespace`: S3 bucket namespace +* `public_endpoint`: S3 endpoint that the user finally accesses(ex. "https://s3.dualstack.ap-northeast-1.amazonaws.com") +* `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc. +For example, when using CDN to S3 virtual host format, set "". +At this time, write CNAME to CDN in public_endpoint. + +## Pleroma.Upload.Filter.Mogrify + +* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`. + +## Pleroma.Upload.Filter.Dedupe + +No specific configuration. + +## Pleroma.Upload.Filter.AnonymizeFilename + +This filter replaces the filename (not the path) of an upload. For complete obfuscation, add +`Pleroma.Upload.Filter.Dedupe` before AnonymizeFilename. + +* `text`: Text to replace filenames in links. If empty, `{random}.extension` will be used. You can get the original filename extension by using `{extension}`, for example `custom-file-name.{extension}`. + +## Pleroma.Emails.Mailer +* `adapter`: one of the mail adapters listed in [Swoosh readme](https://github.com/swoosh/swoosh#adapters), or `Swoosh.Adapters.Local` for in-memory mailbox. +* `api_key` / `password` and / or other adapter-specific settings, per the above documentation. +* `enabled`: Allows enable/disable send emails. Default: `false`. + +An example for Sendgrid adapter: + +```elixir +config :pleroma, Pleroma.Emails.Mailer, + adapter: Swoosh.Adapters.Sendgrid, + api_key: "YOUR_API_KEY" +``` + +An example for SMTP adapter: + +```elixir +config :pleroma, Pleroma.Emails.Mailer, + adapter: Swoosh.Adapters.SMTP, + relay: "smtp.gmail.com", + username: "YOUR_USERNAME@gmail.com", + password: "YOUR_SMTP_PASSWORD", + port: 465, + ssl: true, + tls: :always, + auth: :always +``` + +## :uri_schemes +* `valid_schemes`: List of the scheme part that is considered valid to be an URL + +## :instance +* `name`: The instance’s name +* `email`: Email used to reach an Administrator/Moderator of the instance +* `notify_email`: Email used for notifications. +* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance`` +* `limit`: Posts character limit (CW/Subject included in the counter) +* `remote_limit`: Hard character limit beyond which remote posts will be dropped. +* `upload_limit`: File size limit of uploads (except for avatar, background, banner) +* `avatar_upload_limit`: File size limit of user’s profile avatars +* `background_upload_limit`: File size limit of user’s profile backgrounds +* `banner_upload_limit`: File size limit of user’s profile banners +* `poll_limits`: A map with poll limits for **local** polls + * `max_options`: Maximum number of options + * `max_option_chars`: Maximum number of characters per option + * `min_expiration`: Minimum expiration time (in seconds) + * `max_expiration`: Maximum expiration time (in seconds) +* `registrations_open`: Enable registrations for anyone, invitations can be enabled when false. +* `invites_enabled`: Enable user invitations for admins (depends on `registrations_open: false`). +* `account_activation_required`: Require users to confirm their emails before signing in. +* `federating`: Enable federation with other instances +* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes. +* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it. +* `allow_relay`: Enable Pleroma’s Relay, which makes it possible to follow a whole instance +* `rewrite_policy`: Message Rewrite Policy, either one or a list. Here are the ones available by default: + * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default) + * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production + * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See ``:mrf_simple`` section) + * `Pleroma.Web.ActivityPub.MRF.TagPolicy`: Applies policies to individual users based on tags, which can be set using pleroma-fe/admin-fe/any other app that supports Pleroma Admin API. For example it allows marking posts from individual users nsfw (sensitive) + * `Pleroma.Web.ActivityPub.MRF.SubchainPolicy`: Selectively runs other MRF policies when messages match (see ``:mrf_subchain`` section) + * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See ``:mrf_rejectnonpublic`` section) + * `Pleroma.Web.ActivityPub.MRF.EnsureRePrepended`: Rewrites posts to ensure that replies to posts with subjects do not have an identical subject and instead begin with re:. + * `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links. + * `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed. + * `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (see `:mrf_mention` section) + * `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (see `:mrf_vocabulary` section) +* `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. +* `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send. +* `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json`` +* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML) +* `mrf_transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). +* `mrf_transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. +* `scope_copy`: Copy the scope (private/unlisted/public) in replies to posts by default. +* `subject_line_behavior`: Allows changing the default behaviour of subject lines in replies. Valid values: + * "email": Copy and preprend re:, as in email. + * "masto": Copy verbatim, as in Mastodon. + * "noop": Don't copy the subject. +* `always_show_subject_input`: When set to false, auto-hide the subject field when it's empty. +* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with + older software for theses nicknames. +* `max_pinned_statuses`: The maximum number of pinned statuses. `0` will disable the feature. +* `autofollowed_nicknames`: Set to nicknames of (local) users that every new user should automatically follow. +* `no_attachment_links`: Set to true to disable automatically adding attachment link text to statuses +* `welcome_message`: A message that will be send to a newly registered users as a direct message. +* `welcome_user_nickname`: The nickname of the local user that sends the welcome message. +* `max_report_comment_size`: The maximum size of the report comment (Default: `1000`) +* `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). Default: `false`. +* `healthcheck`: If set to true, system data will be shown on ``/api/pleroma/healthcheck``. +* `remote_post_retention_days`: The default amount of days to retain remote posts when pruning the database. +* `user_bio_length`: A user bio maximum length (default: `5000`) +* `user_name_length`: A user name maximum length (default: `100`) +* `skip_thread_containment`: Skip filter out broken threads. The default is `false`. +* `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. +* `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. +* `max_account_fields`: The maximum number of custom fields in the user profile (default: `10`) +* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `20`) +* `account_field_name_length`: An account field name maximum length (default: `512`) +* `account_field_value_length`: An account field value maximum length (default: `512`) +* `external_user_synchronization`: Enabling following/followers counters synchronization for external users. + + + +## :logger +* `backends`: `:console` is used to send logs to stdout, `{ExSyslogger, :ex_syslogger}` to log to syslog, and `Quack.Logger` to log to Slack + +An example to enable ONLY ExSyslogger (f/ex in ``prod.secret.exs``) with info and debug suppressed: +```elixir +config :logger, + backends: [{ExSyslogger, :ex_syslogger}] + +config :logger, :ex_syslogger, + level: :warn +``` + +Another example, keeping console output and adding the pid to syslog output: +```elixir +config :logger, + backends: [:console, {ExSyslogger, :ex_syslogger}] + +config :logger, :ex_syslogger, + level: :warn, + option: [:pid, :ndelay] +``` + +See: [logger’s documentation](https://hexdocs.pm/logger/Logger.html) and [ex_syslogger’s documentation](https://hexdocs.pm/ex_syslogger/) + +An example of logging info to local syslog, but warn to a Slack channel: +```elixir +config :logger, + backends: [ {ExSyslogger, :ex_syslogger}, Quack.Logger ], + level: :info + +config :logger, :ex_syslogger, + level: :info, + ident: "pleroma", + format: "$metadata[$level] $message" + +config :quack, + level: :warn, + meta: [:all], + webhook_url: "https://hooks.slack.com/services/YOUR-API-KEY-HERE" +``` + +See the [Quack Github](https://github.com/azohra/quack) for more details + +## :frontend_configurations + +This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` and `masto_fe` are configured. + +Frontends can access these settings at `/api/pleroma/frontend_configurations` + +To add your own configuration for PleromaFE, use it like this: + +```elixir +config :pleroma, :frontend_configurations, + pleroma_fe: %{ + theme: "pleroma-dark", + # ... see /priv/static/static/config.json for the available keys. +}, + masto_fe: %{ + showInstanceSpecificPanel: true + } +``` + +These settings **need to be complete**, they will override the defaults. + +NOTE: for versions < 1.0, you need to set [`:fe`](#fe) to false, as shown a few lines below. + +## :fe +__THIS IS DEPRECATED__ + +If you are using this method, please change it to the [`frontend_configurations`](#frontend_configurations) method. +Please **set this option to false** in your config like this: + +```elixir +config :pleroma, :fe, false +``` + +This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:instance`` is set to false. + +* `theme`: Which theme to use, they are defined in ``styles.json`` +* `logo`: URL of the logo, defaults to Pleroma’s logo +* `logo_mask`: Whether to use only the logo's shape as a mask (true) or as a regular image (false) +* `logo_margin`: What margin to use around the logo +* `background`: URL of the background, unless viewing a user profile with a background that is set +* `redirect_root_no_login`: relative URL which indicates where to redirect when a user isn’t logged in. +* `redirect_root_login`: relative URL which indicates where to redirect when a user is logged in. +* `show_instance_panel`: Whenether to show the instance’s specific panel. +* `scope_options_enabled`: Enable setting an notice visibility and subject/CW when posting +* `formatting_options_enabled`: Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to ``:instance, allowed_post_formats`` +* `collapse_message_with_subjects`: When a message has a subject(aka Content Warning), collapse it by default +* `hide_post_stats`: Hide notices statistics(repeats, favorites, …) +* `hide_user_stats`: Hide profile statistics(posts, posts per day, followers, followings, …) + +## :assets + +This section configures assets to be used with various frontends. Currently the only option +relates to mascots on the mastodon frontend + +* `mascots`: KeywordList of mascots, each element __MUST__ contain both a `url` and a + `mime_type` key. +* `default_mascot`: An element from `mascots` - This will be used as the default mascot + on MastoFE (default: `:pleroma_fox_tan`) + +## :mrf_simple +* `media_removal`: List of instances to remove medias from +* `media_nsfw`: List of instances to put medias as NSFW(sensitive) from +* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline +* `reject`: List of instances to reject any activities from +* `accept`: List of instances to accept any activities from +* `report_removal`: List of instances to reject reports from +* `avatar_removal`: List of instances to strip avatars from +* `banner_removal`: List of instances to strip banners from + +## :mrf_subchain +This policy processes messages through an alternate pipeline when a given message matches certain criteria. +All criteria are configured as a map of regular expressions to lists of policy modules. + +* `match_actor`: Matches a series of regular expressions against the actor field. + +Example: + +``` +config :pleroma, :mrf_subchain, + match_actor: %{ + ~r/https:\/\/example.com/s => [Pleroma.Web.ActivityPub.MRF.DropPolicy] + } +``` + +## :mrf_rejectnonpublic +* `allow_followersonly`: whether to allow followers-only posts +* `allow_direct`: whether to allow direct messages + +## :mrf_hellthread +* `delist_threshold`: Number of mentioned users after which the message gets delisted (the message can still be seen, but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable. +* `reject_threshold`: Number of mentioned users after which the messaged gets rejected. Set to 0 to disable. + +## :mrf_keyword +* `reject`: A list of patterns which result in message being rejected, each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) +* `federated_timeline_removal`: A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) +* `replace`: A list of tuples containing `{pattern, replacement}`, `pattern` can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) + +## :mrf_mention +* `actors`: A list of actors, for which to drop any posts mentioning. + +## :mrf_vocabulary +* `accept`: A list of ActivityStreams terms to accept. If empty, all supported messages are accepted. +* `reject`: A list of ActivityStreams terms to reject. If empty, no messages are rejected. + +## :media_proxy +* `enabled`: Enables proxying of remote media to the instance’s proxy +* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts. +* `proxy_opts`: All options defined in `Pleroma.ReverseProxy` documentation, defaults to `[max_body_length: (25*1_048_576)]`. +* `whitelist`: List of domains to bypass the mediaproxy + +## :gopher +* `enabled`: Enables the gopher interface +* `ip`: IP address to bind to +* `port`: Port to bind to +* `dstport`: Port advertised in urls (optional, defaults to `port`) + +## Pleroma.Web.Endpoint +`Phoenix` endpoint configuration, all configuration options can be viewed [here](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#module-dynamic-configuration), only common options are listed here +* `http` - a list containing http protocol configuration, all configuration options can be viewed [here](https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html#module-options), only common options are listed here. For deployment using docker, you need to set this to `[ip: {0,0,0,0}, port: 4000]` to make pleroma accessible from other containers (such as your nginx server). + - `ip` - a tuple consisting of 4 integers + - `port` +* `url` - a list containing the configuration for generating urls, accepts + - `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`) + - `scheme` - e.g `http`, `https` + - `port` + - `path` +* `extra_cookie_attrs` - a list of `Key=Value` strings to be added as non-standard cookie attributes. Defaults to `["SameSite=Lax"]`. See the [SameSite article](https://www.owasp.org/index.php/SameSite) on OWASP for more info. + + + +**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need + +Example: +```elixir +config :pleroma, Pleroma.Web.Endpoint, + url: [host: "example.com", port: 2020, scheme: "https"], + http: [ + # start copied from config.exs + dispatch: [ + {:_, + [ + {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, + {"/websocket", Phoenix.Endpoint.CowboyWebSocket, + {Phoenix.Transports.WebSocket, + {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}}, + {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} + ]} + # end copied from config.exs + ], + port: 8080, + ip: {127, 0, 0, 1} + ] +``` + +This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020` + +## :activitypub +* ``unfollow_blocked``: Whether blocks result in people getting unfollowed +* ``outgoing_blocks``: Whether to federate blocks to other instances +* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question +* ``sign_object_fetches``: Sign object fetches with HTTP signatures + +## :http_security +* ``enabled``: Whether the managed content security policy is enabled +* ``sts``: Whether to additionally send a `Strict-Transport-Security` header +* ``sts_max_age``: The maximum age for the `Strict-Transport-Security` header if sent +* ``ct_max_age``: The maximum age for the `Expect-CT` header if sent +* ``referrer_policy``: The referrer policy to use, either `"same-origin"` or `"no-referrer"` +* ``report_uri``: Adds the specified url to `report-uri` and `report-to` group in CSP header. + +## :mrf_user_allowlist + +The keys in this section are the domain names that the policy should apply to. +Each key should be assigned a list of users that should be allowed through by +their ActivityPub ID. + +An example: + +```elixir +config :pleroma, :mrf_user_allowlist, + "example.org": ["https://example.org/users/admin"] +``` + +## :web_push_encryption, :vapid_details + +Web Push Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it. + +* ``subject``: a mailto link for the administrative contact. It’s best if this email is not a personal email address, but rather a group email so that if a person leaves an organization, is unavailable for an extended period, or otherwise can’t respond, someone else on the list can. +* ``public_key``: VAPID public key +* ``private_key``: VAPID private key + +## Pleroma.Captcha +* `enabled`: Whether the captcha should be shown on registration +* `method`: The method/service to use for captcha +* `seconds_valid`: The time in seconds for which the captcha is valid + +### Pleroma.Captcha.Kocaptcha +Kocaptcha is a very simple captcha service with a single API endpoint, +the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint +`https://captcha.kotobank.ch` is hosted by the developer. + +* `endpoint`: the kocaptcha endpoint to use + +## :admin_token + +Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the 'admin_token' parameter. Example: + +```elixir +config :pleroma, :admin_token, "somerandomtoken" +``` + +You can then do + +```sh +curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken" +``` + +## :pleroma_job_queue + +[Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs. + +Pleroma has the following queues: + +* `federator_outgoing` - Outgoing federation +* `federator_incoming` - Incoming federation +* `mailer` - Email sender, see [`Pleroma.Emails.Mailer`](#pleroma-emails-mailer) +* `transmogrifier` - Transmogrifier +* `web_push` - Web push notifications +* `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivities`](#pleromascheduledactivity) + +Example: + +```elixir +config :pleroma_job_queue, :queues, + federator_incoming: 50, + federator_outgoing: 50 +``` + +This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the `max_jobs` set to `50`. + +## Pleroma.Web.Federator.RetryQueue + +* `enabled`: If set to `true`, failed federation jobs will be retried +* `max_jobs`: The maximum amount of parallel federation jobs running at the same time. +* `initial_timeout`: The initial timeout in seconds +* `max_retries`: The maximum number of times a federation job is retried + +## Pleroma.Web.Metadata +* `providers`: a list of metadata providers to enable. Providers available: + * Pleroma.Web.Metadata.Providers.OpenGraph + * Pleroma.Web.Metadata.Providers.TwitterCard + * Pleroma.Web.Metadata.Providers.RelMe - add links from user bio with rel=me into the `
` as `` +* `unfurl_nsfw`: If set to `true` nsfw attachments will be shown in previews + +## :rich_media +* `enabled`: if enabled the instance will parse metadata from attached links to generate link previews +* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`. +* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"] +* `parsers`: list of Rich Media parsers + +## :fetch_initial_posts +* `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts +* `pages`: the amount of pages to fetch + +## :hackney_pools + +Advanced. Tweaks Hackney (http client) connections pools. + +There's three pools used: + +* `:federation` for the federation jobs. + You may want this pool max_connections to be at least equal to the number of federator jobs + retry queue jobs. +* `:media` for rich media, media proxy +* `:upload` for uploaded media (if using a remote uploader and `proxy_remote: true`) + +For each pool, the options are: + +* `max_connections` - how much connections a pool can hold +* `timeout` - retention duration for connections + +## :auto_linker + +Configuration for the `auto_linker` library: + +* `class: "auto-linker"` - specify the class to be added to the generated link. false to clear +* `rel: "noopener noreferrer"` - override the rel attribute. false to clear +* `new_window: true` - set to false to remove `target='_blank'` attribute +* `scheme: false` - Set to true to link urls with schema `http://google.com` +* `truncate: false` - Set to a number to truncate urls longer then the number. Truncated urls will end in `..` +* `strip_prefix: true` - Strip the scheme prefix +* `extra: false` - link urls with rarely used schemes (magnet, ipfs, irc, etc.) + +Example: + +```elixir +config :auto_linker, + opts: [ + scheme: true, + extra: true, + class: false, + strip_prefix: false, + new_window: false, + rel: false + ] +``` + +## Pleroma.ScheduledActivity + +* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`) +* `total_user_limit`: the number of scheduled activities a user is allowed to create in total (Default: `300`) +* `enabled`: whether scheduled activities are sent to the job queue to be executed + +## Pleroma.ActivityExpiration + +# `enabled`: whether expired activities will be sent to the job queue to be deleted + +## Pleroma.Web.Auth.Authenticator + +* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator +* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication + +## :ldap + +Use LDAP for user authentication. When a user logs in to the Pleroma +instance, the name and password will be verified by trying to authenticate +(bind) to an LDAP server. If a user exists in the LDAP directory but there +is no account with the same name yet on the Pleroma instance then a new +Pleroma account will be created with the same name as the LDAP user name. + +* `enabled`: enables LDAP authentication +* `host`: LDAP server hostname +* `port`: LDAP port, e.g. 389 or 636 +* `ssl`: true to use SSL, usually implies the port 636 +* `sslopts`: additional SSL options +* `tls`: true to start TLS, usually implies the port 389 +* `tlsopts`: additional TLS options +* `base`: LDAP base, e.g. "dc=example,dc=com" +* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base" + +## BBS / SSH access + +To enable simple command line interface accessible over ssh, add a setting like this to your configuration file: + +```exs +app_dir = File.cwd! +priv_dir = Path.join([app_dir, "priv/ssh_keys"]) + +config :esshd, + enabled: true, + priv_dir: priv_dir, + handler: "Pleroma.BBS.Handler", + port: 10_022, + password_authenticator: "Pleroma.BBS.Authenticator" +``` + +Feel free to adjust the priv_dir and port number. Then you will have to create the key for the keys (in the example `priv/ssh_keys`) and create the host keys with `ssh-keygen -m PEM -N "" -b 2048 -t rsa -f ssh_host_rsa_key`. After restarting, you should be able to connect to your Pleroma instance with `ssh username@server -p $PORT` + +## :auth + +* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator +* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication + +Authentication / authorization settings. + +* `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`. +* `oauth_consumer_template`: OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`. +* `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by `OAUTH_CONSUMER_STRATEGIES` environment variable. Each entry in this space-delimited string should be of format `` or `:` (e.g. `twitter` or `keycloak:ueberauth_keycloak_strategy` in case dependency is named differently than `ueberauth_`). + +## :email_notifications + +Email notifications settings. + + - digest - emails of "what you've missed" for users who have been + inactive for a while. + - active: globally enable or disable digest emails + - schedule: When to send digest email, in [crontab format](https://en.wikipedia.org/wiki/Cron). + "0 0 * * 0" is the default, meaning "once a week at midnight on Sunday morning" + - interval: Minimum interval between digest emails to one user + - inactivity_threshold: Minimum user inactivity threshold + +## Pleroma.Emails.UserEmail + +- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo. +- `:styling` - a map with color settings for email templates. + +## OAuth consumer mode + +OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.). +Implementation is based on Ueberauth; see the list of [available strategies](https://github.com/ueberauth/ueberauth/wiki/List-of-Strategies). + +Note: each strategy is shipped as a separate dependency; in order to get the strategies, run `OAUTH_CONSUMER_STRATEGIES="..." mix deps.get`, +e.g. `OAUTH_CONSUMER_STRATEGIES="twitter facebook google microsoft" mix deps.get`. +The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx.server` in case you enable any strategies. + +Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies. + +Note: make sure that `"SameSite=Lax"` is set in `extra_cookie_attrs` when you have this feature enabled. OAuth consumer mode will not work with `"SameSite=Strict"` + +* For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https:///oauth/twitter/callback + +* For Facebook, [register an app](https://developers.facebook.com/apps), configure callback URL to https:///oauth/facebook/callback, enable Facebook Login service at https://developers.facebook.com/apps//fb-login/settings/ + +* For Google, [register an app](https://console.developers.google.com), configure callback URL to https:///oauth/google/callback + +* For Microsoft, [register an app](https://portal.azure.com), configure callback URL to https:///oauth/microsoft/callback + +Once the app is configured on external OAuth provider side, add app's credentials and strategy-specific settings (if any — e.g. see Microsoft below) to `config/prod.secret.exs`, +per strategy's documentation (e.g. [ueberauth_twitter](https://github.com/ueberauth/ueberauth_twitter)). Example config basing on environment variables: + +```elixir +# Twitter +config :ueberauth, Ueberauth.Strategy.Twitter.OAuth, + consumer_key: System.get_env("TWITTER_CONSUMER_KEY"), + consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET") + +# Facebook +config :ueberauth, Ueberauth.Strategy.Facebook.OAuth, + client_id: System.get_env("FACEBOOK_APP_ID"), + client_secret: System.get_env("FACEBOOK_APP_SECRET"), + redirect_uri: System.get_env("FACEBOOK_REDIRECT_URI") + +# Google +config :ueberauth, Ueberauth.Strategy.Google.OAuth, + client_id: System.get_env("GOOGLE_CLIENT_ID"), + client_secret: System.get_env("GOOGLE_CLIENT_SECRET"), + redirect_uri: System.get_env("GOOGLE_REDIRECT_URI") + +# Microsoft +config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth, + client_id: System.get_env("MICROSOFT_CLIENT_ID"), + client_secret: System.get_env("MICROSOFT_CLIENT_SECRET") + +config :ueberauth, Ueberauth, + providers: [ + microsoft: {Ueberauth.Strategy.Microsoft, [callback_params: []]} + ] + +# Keycloak +# Note: make sure to add `keycloak:ueberauth_keycloak_strategy` entry to `OAUTH_CONSUMER_STRATEGIES` environment variable +keycloak_url = "https://publicly-reachable-keycloak-instance.org:8080" + +config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth, + client_id: System.get_env("KEYCLOAK_CLIENT_ID"), + client_secret: System.get_env("KEYCLOAK_CLIENT_SECRET"), + site: keycloak_url, + authorize_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/auth", + token_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/token", + userinfo_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/userinfo", + token_method: :post + +config :ueberauth, Ueberauth, + providers: [ + keycloak: {Ueberauth.Strategy.Keycloak, [uid_field: :email]} + ] +``` + +## OAuth 2.0 provider - :oauth2 + +Configure OAuth 2 provider capabilities: + +* `token_expires_in` - The lifetime in seconds of the access token. +* `issue_new_refresh_token` - Keeps old refresh token or generate new refresh token when to obtain an access token. +* `clean_expired_tokens` - Enable a background job to clean expired oauth tokens. Defaults to `false`. +* `clean_expired_tokens_interval` - Interval to run the job to clean expired tokens. Defaults to `86_400_000` (24 hours). + +## :emoji +* `shortcode_globs`: Location of custom emoji files. `*` can be used as a wildcard. Example `["/emoji/custom/**/*.png"]` +* `pack_extensions`: A list of file extensions for emojis, when no emoji.txt for a pack is present. Example `[".png", ".gif"]` +* `groups`: Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname and the value the location or array of locations. `*` can be used as a wildcard. Example `[Custom: ["/emoji/*.png", "/emoji/custom/*.png"]]` +* `default_manifest`: Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays). + +## Database options + +### RUM indexing for full text search +* `rum_enabled`: If RUM indexes should be used. Defaults to `false`. + +RUM indexes are an alternative indexing scheme that is not included in PostgreSQL by default. While they may eventually be mainlined, for now they have to be installed as a PostgreSQL extension from https://github.com/postgrespro/rum. + +Their advantage over the standard GIN indexes is that they allow efficient ordering of search results by timestamp, which makes search queries a lot faster on larger servers, by one or two orders of magnitude. They take up around 3 times as much space as GIN indexes. + +To enable them, both the `rum_enabled` flag has to be set and the following special migration has to be run: + +`mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/` + +This will probably take a long time. + +## :rate_limit + +This is an advanced feature and disabled by default. + +A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: + +* The first element: `scale` (Integer). The time scale in milliseconds. +* The second element: `limit` (Integer). How many requests to limit in the time scale provided. + +It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated. + +See [`Pleroma.Plugs.RateLimiter`](Pleroma.Plugs.RateLimiter.html) documentation for examples. + +Supported rate limiters: + +* `:search` for the search requests (account & status search etc.) +* `:app_account_creation` for registering user accounts from the same IP address +* `:relations_actions` for actions on relations with all users (follow, unfollow) +* `:relation_id_action` for actions on relation with a specific user (follow, unfollow) +* `:statuses_actions` for create / delete / fav / unfav / reblog / unreblog actions on any statuses +* `:status_id_action` for fav / unfav or reblog / unreblog actions on the same status by the same user + +## :web_cache_ttl + +The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration. + +Available caches: + +* `:activity_pub` - activity pub routes (except question activities). Defaults to `nil` (no expiration). +* `:activity_pub_question` - activity pub routes (question activities). Defaults to `30_000` (30 seconds). From 4da0da9aa46f0970735f398a1786902f4e3a86eb Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 13 Sep 2019 19:13:04 +0300 Subject: [PATCH 067/272] don't track generated_config.md --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9591f9976..4e71a7df0 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ erl_crash.dump # Prevent committing docs files /priv/static/doc/* +docs/generated_config.md # Code test coverage /cover From ac4a748fad34c02647bf72e802cd9d74205681fe Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Sep 2019 19:28:35 +0300 Subject: [PATCH 068/272] Disallow NULLs in deliveries --- lib/pleroma/delivery.ex | 1 + priv/repo/migrations/20190912065617_create_deliveries.exs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/delivery.ex b/lib/pleroma/delivery.ex index 38c148c34..29a1e5a77 100644 --- a/lib/pleroma/delivery.ex +++ b/lib/pleroma/delivery.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Delivery do def changeset(delivery, params \\ %{}) do delivery |> cast(params, [:user_id, :object_id]) + |> validate_required([:user_id, :object_id]) |> foreign_key_constraint(:object_id) |> foreign_key_constraint(:user_id) |> unique_constraint(:user_id, name: :deliveries_user_id_object_id_index) diff --git a/priv/repo/migrations/20190912065617_create_deliveries.exs b/priv/repo/migrations/20190912065617_create_deliveries.exs index 92ca5650a..79071a799 100644 --- a/priv/repo/migrations/20190912065617_create_deliveries.exs +++ b/priv/repo/migrations/20190912065617_create_deliveries.exs @@ -3,8 +3,8 @@ defmodule Pleroma.Repo.Migrations.CreateDeliveries do def change do create_if_not_exists table(:deliveries) do - add(:object_id, references(:objects, type: :id)) - add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:object_id, references(:objects, type: :id), null: false) + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all), null: false) end create_if_not_exists index(:deliveries, :object_id, name: :deliveries_object_id) create_if_not_exists(unique_index(:deliveries, [:user_id, :object_id])) From 5c5ebd38619bb853a58374918fd8983569ba7c0b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 14 Sep 2019 01:50:15 +0300 Subject: [PATCH 069/272] Mastodon API: Respect post privacy in favourited/reblogged endpoints --- CHANGELOG.md | 1 + .../controllers/mastodon_api_controller.ex | 4 ++ .../mastodon_api_controller_test.exs | 53 ++++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fe3bf687..0c5e43123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Security - OStatus: eliminate the possibility of a protocol downgrade attack. - OStatus: prevent following locked accounts, bypassing the approval process. +- Mastodon API: respect post privacy in `/api/v1/statuses/:id/{favourited,reblogged}_by` ### Removed - **Breaking:** GNU Social API with Qvitter extensions support diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 0940e07a6..060137b80 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -842,6 +842,7 @@ def get_mascot(%{assigns: %{user: user}} = conn, _params) do def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{} = activity <- Activity.get_by_id_with_object(id), + {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do q = from(u in User, where: u.ap_id in ^likes) @@ -853,12 +854,14 @@ def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do |> put_view(AccountView) |> render("accounts.json", %{for: user, users: users, as: :user}) else + {:visible, false} -> {:error, :not_found} _ -> json(conn, []) end end def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{} = activity <- Activity.get_by_id_with_object(id), + {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, %Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do q = from(u in User, where: u.ap_id in ^announces) @@ -870,6 +873,7 @@ def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do |> put_view(AccountView) |> render("accounts.json", %{for: user, users: users, as: :user}) else + {:visible, false} -> {:error, :not_found} _ -> json(conn, []) end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 806ae7e69..c9bce1439 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3698,7 +3698,7 @@ test "returns 404 when poll is private and not available for user", %{conn: conn build_conn() |> assign(:user, user) - [conn: conn, activity: activity] + [conn: conn, activity: activity, user: user] end test "returns users who have favorited the status", %{conn: conn, activity: activity} do @@ -3758,6 +3758,32 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti [%{"id" => id}] = response assert id == other_user.id end + + test "requires authentifucation for private posts", %{conn: conn, user: user} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "@#{other_user.nickname} wanna get some #cofe together?", + "visibility" => "direct" + }) + + {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + + conn + |> assign(:user, nil) + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(404) + + response = + build_conn() + |> assign(:user, other_user) + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(200) + + [%{"id" => id}] = response + assert id == other_user.id + end end describe "GET /api/v1/statuses/:id/reblogged_by" do @@ -3769,7 +3795,7 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti build_conn() |> assign(:user, user) - [conn: conn, activity: activity] + [conn: conn, activity: activity, user: user] end test "returns users who have reblogged the status", %{conn: conn, activity: activity} do @@ -3829,6 +3855,29 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti [%{"id" => id}] = response assert id == other_user.id end + + test "requires authentifucation for private posts", %{conn: conn, user: user} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "@#{other_user.nickname} wanna get some #cofe together?", + "visibility" => "direct" + }) + + conn + |> assign(:user, nil) + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(404) + + response = + build_conn() + |> assign(:user, other_user) + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(200) + + assert [] == response + end end describe "POST /auth/password, with valid parameters" do From 85b6144ffd9e96fc79608847fe739a40ca094207 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 14 Sep 2019 10:46:35 +0000 Subject: [PATCH 070/272] Apply suggestion to test/web/mastodon_api/mastodon_api_controller_test.exs --- test/web/mastodon_api/mastodon_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index c9bce1439..013a838b8 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3759,7 +3759,7 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti assert id == other_user.id end - test "requires authentifucation for private posts", %{conn: conn, user: user} do + test "requires authentification for private posts", %{conn: conn, user: user} do other_user = insert(:user) {:ok, activity} = From a78a7ee455c4e8f4c2aab15a15626237b2b90399 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 14 Sep 2019 10:50:08 +0000 Subject: [PATCH 071/272] Apply suggestion to test/web/mastodon_api/mastodon_api_controller_test.exs --- test/web/mastodon_api/mastodon_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 013a838b8..061c3a8ad 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3856,7 +3856,7 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti assert id == other_user.id end - test "requires authentifucation for private posts", %{conn: conn, user: user} do + test "requires authentification for private posts", %{conn: conn, user: user} do other_user = insert(:user) {:ok, activity} = From b870ae08fd19acd7c40e4353e657e6a1ed1b34c5 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Sat, 14 Sep 2019 19:31:20 +0700 Subject: [PATCH 072/272] Fix `Activity.all_by_actor_and_id/2` test --- test/activity_test.exs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/activity_test.exs b/test/activity_test.exs index f9f789a76..275cab81e 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -213,7 +213,11 @@ test "all_by_actor_and_id/2" do assert [] == Activity.all_by_actor_and_id(user, []) - assert [%Activity{id: ^id2}, %Activity{id: ^id1}] = - Activity.all_by_actor_and_id(user.ap_id, [id1, id2]) + activities = + user.ap_id + |> Activity.all_by_actor_and_id([id1, id2]) + |> Enum.sort(&(&1.id < &2.id)) + + assert [%Activity{id: ^id1}, %Activity{id: ^id2}] = activities end end From e127b9ab6d01da48ebad188d2b9fcf7cb8a41578 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sat, 14 Sep 2019 16:28:59 +0300 Subject: [PATCH 073/272] [#1149] Rewritten readme as config/description.exs. --- config/description.exs | 198 ++++++++++++++++++++++++++--------------- 1 file changed, 126 insertions(+), 72 deletions(-) diff --git a/config/description.exs b/config/description.exs index c5ae63915..be5eb0cc3 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1778,87 +1778,141 @@ group: :pleroma_job_queue, key: :queues, type: :group, - description: "Pleroma Job Queue configuration: a list of queues with maximum concurrent jobs", - children: [ - %{ - key: :federator_outgoing, - type: :integer, - description: "Outgoing federation queue", - suggestions: [50] - }, - %{ - key: :federator_incoming, - type: :integer, - description: "Incoming federation queue", - suggestions: [50] - }, - %{ - key: :mailer, - type: :integer, - description: "Email sender queue, see Pleroma.Emails.Mailer", - suggestions: [10] - }, - %{ - key: :web_push, - type: :integer, - description: "Web push notifications queue", - suggestions: [50] - }, - %{ - key: :transmogrifier, - type: :integer, - description: "Transmogrifier queue", - suggestions: [20] - }, - %{ - key: :scheduled_activities, - type: :integer, - description: "Scheduled activities queue, see Pleroma.ScheduledActivities", - suggestions: [10] - }, - %{ - key: :activity_expiration, - type: :integer, - description: "Activity expiration queue", - suggestions: [10] - }, - %{ - key: :background, - type: :integer, - description: "Background queue", - suggestions: [5] - } - ] + description: "[Deprecated] Replaced with `Oban`/`:queues` (keeping the same format)", + children: [] }, %{ group: :pleroma, key: Pleroma.Web.Federator.RetryQueue, type: :group, - description: "", + description: "[Deprecated] See `Oban` and `:workers` sections for configuration notes", children: [ - %{ - key: :enabled, - type: :boolean, - description: "If set to true, failed federation jobs will be retried", - suggestions: [true, false] - }, - %{ - key: :max_jobs, - type: :integer, - description: "The maximum amount of parallel federation jobs running at the same time", - suggestions: [20] - }, - %{ - key: :initial_timeout, - type: :integer, - description: "The initial timeout in seconds", - suggestions: [30] - }, %{ key: :max_retries, type: :integer, - description: "The maximum number of times a federation job is retried", - suggestions: [5] + description: "[Deprecated] Replaced as `Oban`/`:queues`/`:outgoing_federation` value", + suggestions: [] + } + ] + }, + %{ + group: :pleroma, + key: Oban, + type: :group, + description: """ + [Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration. + + Note: if you are running PostgreSQL in [`silent_mode`](https://postgresqlco.nf/en/doc/param/silent_mode?version=9.1), + it's advised to set [`log_destination`](https://postgresqlco.nf/en/doc/param/log_destination?version=9.1) to `syslog`, + otherwise `postmaster.log` file may grow because of "you don't own a lock of type ShareLock" warnings + (see https://github.com/sorentwo/oban/issues/52). + """, + children: [ + %{ + key: :repo, + type: :module, + description: "Application's Ecto repo", + suggestions: [Pleroma.Repo] + }, + %{ + key: :verbose, + type: :boolean, + description: "Logs verbose mode", + suggestions: [false, true] + }, + %{ + key: :prune, + type: [:atom, :tuple], + description: + "Non-retryable jobs [pruning settings](https://github.com/sorentwo/oban#pruning)", + suggestions: [:disabled, {:maxlen, 1500}, {:maxage, 60 * 60}] + }, + %{ + key: :queues, + type: :keyword, + description: + "Background jobs queues (keys: queues, values: max numbers of concurrent jobs)", + suggestions: [ + [ + activity_expiration: 10, + background: 5, + federator_incoming: 50, + federator_outgoing: 50, + mailer: 10, + scheduled_activities: 10, + transmogrifier: 20, + web_push: 50 + ] + ], + children: [ + %{ + key: :activity_expiration, + type: :integer, + description: "Activity expiration queue", + suggestions: [10] + }, + %{ + key: :background, + type: :integer, + description: "Background queue", + suggestions: [5] + }, + %{ + key: :federator_incoming, + type: :integer, + description: "Incoming federation queue", + suggestions: [50] + }, + %{ + key: :federator_outgoing, + type: :integer, + description: "Outgoing federation queue", + suggestions: [50] + }, + %{ + key: :mailer, + type: :integer, + description: "Email sender queue, see Pleroma.Emails.Mailer", + suggestions: [10] + }, + %{ + key: :scheduled_activities, + type: :integer, + description: "Scheduled activities queue, see Pleroma.ScheduledActivities", + suggestions: [10] + }, + %{ + key: :transmogrifier, + type: :integer, + description: "Transmogrifier queue", + suggestions: [20] + }, + %{ + key: :web_push, + type: :integer, + description: "Web push notifications queue", + suggestions: [50] + } + ] + } + ] + }, + %{ + group: :pleroma, + key: :workers, + type: :group, + description: "Includes custom worker options not interpretable directly by `Oban`", + children: [ + %{ + key: :retries, + type: :keyword, + description: "Max retry attempts for failed jobs, per `Oban` queue", + suggestions: [ + [ + federator_incoming: 5, + federator_outgoing: 5 + ] + ] } ] }, From 3b8ec98b0e3b3fb2bd333f3be724676c4821366f Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sun, 15 Sep 2019 10:15:57 +0300 Subject: [PATCH 074/272] [#1149] Reinstated docs/config.md changes. --- docs/config.md | 1456 +++++++++++++++++++++++++----------------------- 1 file changed, 755 insertions(+), 701 deletions(-) diff --git a/docs/config.md b/docs/config.md index 066547bb1..270d7fcea 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,701 +1,755 @@ -# Configuration - -This file describe the configuration, it is recommended to edit the relevant *.secret.exs file instead of the others founds in the ``config`` directory. -If you run Pleroma with ``MIX_ENV=prod`` the file is ``prod.secret.exs``, otherwise it is ``dev.secret.exs``. - -## Pleroma.Upload -* `uploader`: Select which `Pleroma.Uploaders` to use -* `filters`: List of `Pleroma.Upload.Filter` to use. -* `link_name`: When enabled Pleroma will add a `name` parameter to the url of the upload, for example `https://instance.tld/media/corndog.png?name=corndog.png`. This is needed to provide the correct filename in Content-Disposition headers when using filters like `Pleroma.Upload.Filter.Dedupe` -* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host. -* `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it. -* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation. - -Note: `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`. - -## Pleroma.Uploaders.Local -* `uploads`: Which directory to store the user-uploads in, relative to pleroma’s working directory - -## Pleroma.Uploaders.S3 -* `bucket`: S3 bucket name -* `bucket_namespace`: S3 bucket namespace -* `public_endpoint`: S3 endpoint that the user finally accesses(ex. "https://s3.dualstack.ap-northeast-1.amazonaws.com") -* `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc. -For example, when using CDN to S3 virtual host format, set "". -At this time, write CNAME to CDN in public_endpoint. - -## Pleroma.Upload.Filter.Mogrify - -* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`. - -## Pleroma.Upload.Filter.Dedupe - -No specific configuration. - -## Pleroma.Upload.Filter.AnonymizeFilename - -This filter replaces the filename (not the path) of an upload. For complete obfuscation, add -`Pleroma.Upload.Filter.Dedupe` before AnonymizeFilename. - -* `text`: Text to replace filenames in links. If empty, `{random}.extension` will be used. You can get the original filename extension by using `{extension}`, for example `custom-file-name.{extension}`. - -## Pleroma.Emails.Mailer -* `adapter`: one of the mail adapters listed in [Swoosh readme](https://github.com/swoosh/swoosh#adapters), or `Swoosh.Adapters.Local` for in-memory mailbox. -* `api_key` / `password` and / or other adapter-specific settings, per the above documentation. -* `enabled`: Allows enable/disable send emails. Default: `false`. - -An example for Sendgrid adapter: - -```elixir -config :pleroma, Pleroma.Emails.Mailer, - adapter: Swoosh.Adapters.Sendgrid, - api_key: "YOUR_API_KEY" -``` - -An example for SMTP adapter: - -```elixir -config :pleroma, Pleroma.Emails.Mailer, - adapter: Swoosh.Adapters.SMTP, - relay: "smtp.gmail.com", - username: "YOUR_USERNAME@gmail.com", - password: "YOUR_SMTP_PASSWORD", - port: 465, - ssl: true, - tls: :always, - auth: :always -``` - -## :uri_schemes -* `valid_schemes`: List of the scheme part that is considered valid to be an URL - -## :instance -* `name`: The instance’s name -* `email`: Email used to reach an Administrator/Moderator of the instance -* `notify_email`: Email used for notifications. -* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance`` -* `limit`: Posts character limit (CW/Subject included in the counter) -* `remote_limit`: Hard character limit beyond which remote posts will be dropped. -* `upload_limit`: File size limit of uploads (except for avatar, background, banner) -* `avatar_upload_limit`: File size limit of user’s profile avatars -* `background_upload_limit`: File size limit of user’s profile backgrounds -* `banner_upload_limit`: File size limit of user’s profile banners -* `poll_limits`: A map with poll limits for **local** polls - * `max_options`: Maximum number of options - * `max_option_chars`: Maximum number of characters per option - * `min_expiration`: Minimum expiration time (in seconds) - * `max_expiration`: Maximum expiration time (in seconds) -* `registrations_open`: Enable registrations for anyone, invitations can be enabled when false. -* `invites_enabled`: Enable user invitations for admins (depends on `registrations_open: false`). -* `account_activation_required`: Require users to confirm their emails before signing in. -* `federating`: Enable federation with other instances -* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes. -* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it. -* `allow_relay`: Enable Pleroma’s Relay, which makes it possible to follow a whole instance -* `rewrite_policy`: Message Rewrite Policy, either one or a list. Here are the ones available by default: - * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default) - * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production - * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See ``:mrf_simple`` section) - * `Pleroma.Web.ActivityPub.MRF.TagPolicy`: Applies policies to individual users based on tags, which can be set using pleroma-fe/admin-fe/any other app that supports Pleroma Admin API. For example it allows marking posts from individual users nsfw (sensitive) - * `Pleroma.Web.ActivityPub.MRF.SubchainPolicy`: Selectively runs other MRF policies when messages match (see ``:mrf_subchain`` section) - * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See ``:mrf_rejectnonpublic`` section) - * `Pleroma.Web.ActivityPub.MRF.EnsureRePrepended`: Rewrites posts to ensure that replies to posts with subjects do not have an identical subject and instead begin with re:. - * `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links. - * `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed. - * `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (see `:mrf_mention` section) - * `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (see `:mrf_vocabulary` section) -* `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. -* `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send. -* `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json`` -* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML) -* `mrf_transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). -* `mrf_transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. -* `scope_copy`: Copy the scope (private/unlisted/public) in replies to posts by default. -* `subject_line_behavior`: Allows changing the default behaviour of subject lines in replies. Valid values: - * "email": Copy and preprend re:, as in email. - * "masto": Copy verbatim, as in Mastodon. - * "noop": Don't copy the subject. -* `always_show_subject_input`: When set to false, auto-hide the subject field when it's empty. -* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with - older software for theses nicknames. -* `max_pinned_statuses`: The maximum number of pinned statuses. `0` will disable the feature. -* `autofollowed_nicknames`: Set to nicknames of (local) users that every new user should automatically follow. -* `no_attachment_links`: Set to true to disable automatically adding attachment link text to statuses -* `welcome_message`: A message that will be send to a newly registered users as a direct message. -* `welcome_user_nickname`: The nickname of the local user that sends the welcome message. -* `max_report_comment_size`: The maximum size of the report comment (Default: `1000`) -* `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). Default: `false`. -* `healthcheck`: If set to true, system data will be shown on ``/api/pleroma/healthcheck``. -* `remote_post_retention_days`: The default amount of days to retain remote posts when pruning the database. -* `user_bio_length`: A user bio maximum length (default: `5000`) -* `user_name_length`: A user name maximum length (default: `100`) -* `skip_thread_containment`: Skip filter out broken threads. The default is `false`. -* `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. -* `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. -* `max_account_fields`: The maximum number of custom fields in the user profile (default: `10`) -* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `20`) -* `account_field_name_length`: An account field name maximum length (default: `512`) -* `account_field_value_length`: An account field value maximum length (default: `512`) -* `external_user_synchronization`: Enabling following/followers counters synchronization for external users. - - - -## :logger -* `backends`: `:console` is used to send logs to stdout, `{ExSyslogger, :ex_syslogger}` to log to syslog, and `Quack.Logger` to log to Slack - -An example to enable ONLY ExSyslogger (f/ex in ``prod.secret.exs``) with info and debug suppressed: -```elixir -config :logger, - backends: [{ExSyslogger, :ex_syslogger}] - -config :logger, :ex_syslogger, - level: :warn -``` - -Another example, keeping console output and adding the pid to syslog output: -```elixir -config :logger, - backends: [:console, {ExSyslogger, :ex_syslogger}] - -config :logger, :ex_syslogger, - level: :warn, - option: [:pid, :ndelay] -``` - -See: [logger’s documentation](https://hexdocs.pm/logger/Logger.html) and [ex_syslogger’s documentation](https://hexdocs.pm/ex_syslogger/) - -An example of logging info to local syslog, but warn to a Slack channel: -```elixir -config :logger, - backends: [ {ExSyslogger, :ex_syslogger}, Quack.Logger ], - level: :info - -config :logger, :ex_syslogger, - level: :info, - ident: "pleroma", - format: "$metadata[$level] $message" - -config :quack, - level: :warn, - meta: [:all], - webhook_url: "https://hooks.slack.com/services/YOUR-API-KEY-HERE" -``` - -See the [Quack Github](https://github.com/azohra/quack) for more details - -## :frontend_configurations - -This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` and `masto_fe` are configured. - -Frontends can access these settings at `/api/pleroma/frontend_configurations` - -To add your own configuration for PleromaFE, use it like this: - -```elixir -config :pleroma, :frontend_configurations, - pleroma_fe: %{ - theme: "pleroma-dark", - # ... see /priv/static/static/config.json for the available keys. -}, - masto_fe: %{ - showInstanceSpecificPanel: true - } -``` - -These settings **need to be complete**, they will override the defaults. - -NOTE: for versions < 1.0, you need to set [`:fe`](#fe) to false, as shown a few lines below. - -## :fe -__THIS IS DEPRECATED__ - -If you are using this method, please change it to the [`frontend_configurations`](#frontend_configurations) method. -Please **set this option to false** in your config like this: - -```elixir -config :pleroma, :fe, false -``` - -This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:instance`` is set to false. - -* `theme`: Which theme to use, they are defined in ``styles.json`` -* `logo`: URL of the logo, defaults to Pleroma’s logo -* `logo_mask`: Whether to use only the logo's shape as a mask (true) or as a regular image (false) -* `logo_margin`: What margin to use around the logo -* `background`: URL of the background, unless viewing a user profile with a background that is set -* `redirect_root_no_login`: relative URL which indicates where to redirect when a user isn’t logged in. -* `redirect_root_login`: relative URL which indicates where to redirect when a user is logged in. -* `show_instance_panel`: Whenether to show the instance’s specific panel. -* `scope_options_enabled`: Enable setting an notice visibility and subject/CW when posting -* `formatting_options_enabled`: Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to ``:instance, allowed_post_formats`` -* `collapse_message_with_subjects`: When a message has a subject(aka Content Warning), collapse it by default -* `hide_post_stats`: Hide notices statistics(repeats, favorites, …) -* `hide_user_stats`: Hide profile statistics(posts, posts per day, followers, followings, …) - -## :assets - -This section configures assets to be used with various frontends. Currently the only option -relates to mascots on the mastodon frontend - -* `mascots`: KeywordList of mascots, each element __MUST__ contain both a `url` and a - `mime_type` key. -* `default_mascot`: An element from `mascots` - This will be used as the default mascot - on MastoFE (default: `:pleroma_fox_tan`) - -## :mrf_simple -* `media_removal`: List of instances to remove medias from -* `media_nsfw`: List of instances to put medias as NSFW(sensitive) from -* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline -* `reject`: List of instances to reject any activities from -* `accept`: List of instances to accept any activities from -* `report_removal`: List of instances to reject reports from -* `avatar_removal`: List of instances to strip avatars from -* `banner_removal`: List of instances to strip banners from - -## :mrf_subchain -This policy processes messages through an alternate pipeline when a given message matches certain criteria. -All criteria are configured as a map of regular expressions to lists of policy modules. - -* `match_actor`: Matches a series of regular expressions against the actor field. - -Example: - -``` -config :pleroma, :mrf_subchain, - match_actor: %{ - ~r/https:\/\/example.com/s => [Pleroma.Web.ActivityPub.MRF.DropPolicy] - } -``` - -## :mrf_rejectnonpublic -* `allow_followersonly`: whether to allow followers-only posts -* `allow_direct`: whether to allow direct messages - -## :mrf_hellthread -* `delist_threshold`: Number of mentioned users after which the message gets delisted (the message can still be seen, but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable. -* `reject_threshold`: Number of mentioned users after which the messaged gets rejected. Set to 0 to disable. - -## :mrf_keyword -* `reject`: A list of patterns which result in message being rejected, each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) -* `federated_timeline_removal`: A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) -* `replace`: A list of tuples containing `{pattern, replacement}`, `pattern` can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) - -## :mrf_mention -* `actors`: A list of actors, for which to drop any posts mentioning. - -## :mrf_vocabulary -* `accept`: A list of ActivityStreams terms to accept. If empty, all supported messages are accepted. -* `reject`: A list of ActivityStreams terms to reject. If empty, no messages are rejected. - -## :media_proxy -* `enabled`: Enables proxying of remote media to the instance’s proxy -* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts. -* `proxy_opts`: All options defined in `Pleroma.ReverseProxy` documentation, defaults to `[max_body_length: (25*1_048_576)]`. -* `whitelist`: List of domains to bypass the mediaproxy - -## :gopher -* `enabled`: Enables the gopher interface -* `ip`: IP address to bind to -* `port`: Port to bind to -* `dstport`: Port advertised in urls (optional, defaults to `port`) - -## Pleroma.Web.Endpoint -`Phoenix` endpoint configuration, all configuration options can be viewed [here](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#module-dynamic-configuration), only common options are listed here -* `http` - a list containing http protocol configuration, all configuration options can be viewed [here](https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html#module-options), only common options are listed here. For deployment using docker, you need to set this to `[ip: {0,0,0,0}, port: 4000]` to make pleroma accessible from other containers (such as your nginx server). - - `ip` - a tuple consisting of 4 integers - - `port` -* `url` - a list containing the configuration for generating urls, accepts - - `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`) - - `scheme` - e.g `http`, `https` - - `port` - - `path` -* `extra_cookie_attrs` - a list of `Key=Value` strings to be added as non-standard cookie attributes. Defaults to `["SameSite=Lax"]`. See the [SameSite article](https://www.owasp.org/index.php/SameSite) on OWASP for more info. - - - -**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need - -Example: -```elixir -config :pleroma, Pleroma.Web.Endpoint, - url: [host: "example.com", port: 2020, scheme: "https"], - http: [ - # start copied from config.exs - dispatch: [ - {:_, - [ - {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, - {"/websocket", Phoenix.Endpoint.CowboyWebSocket, - {Phoenix.Transports.WebSocket, - {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}}, - {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} - ]} - # end copied from config.exs - ], - port: 8080, - ip: {127, 0, 0, 1} - ] -``` - -This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020` - -## :activitypub -* ``unfollow_blocked``: Whether blocks result in people getting unfollowed -* ``outgoing_blocks``: Whether to federate blocks to other instances -* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question -* ``sign_object_fetches``: Sign object fetches with HTTP signatures - -## :http_security -* ``enabled``: Whether the managed content security policy is enabled -* ``sts``: Whether to additionally send a `Strict-Transport-Security` header -* ``sts_max_age``: The maximum age for the `Strict-Transport-Security` header if sent -* ``ct_max_age``: The maximum age for the `Expect-CT` header if sent -* ``referrer_policy``: The referrer policy to use, either `"same-origin"` or `"no-referrer"` -* ``report_uri``: Adds the specified url to `report-uri` and `report-to` group in CSP header. - -## :mrf_user_allowlist - -The keys in this section are the domain names that the policy should apply to. -Each key should be assigned a list of users that should be allowed through by -their ActivityPub ID. - -An example: - -```elixir -config :pleroma, :mrf_user_allowlist, - "example.org": ["https://example.org/users/admin"] -``` - -## :web_push_encryption, :vapid_details - -Web Push Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it. - -* ``subject``: a mailto link for the administrative contact. It’s best if this email is not a personal email address, but rather a group email so that if a person leaves an organization, is unavailable for an extended period, or otherwise can’t respond, someone else on the list can. -* ``public_key``: VAPID public key -* ``private_key``: VAPID private key - -## Pleroma.Captcha -* `enabled`: Whether the captcha should be shown on registration -* `method`: The method/service to use for captcha -* `seconds_valid`: The time in seconds for which the captcha is valid - -### Pleroma.Captcha.Kocaptcha -Kocaptcha is a very simple captcha service with a single API endpoint, -the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint -`https://captcha.kotobank.ch` is hosted by the developer. - -* `endpoint`: the kocaptcha endpoint to use - -## :admin_token - -Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the 'admin_token' parameter. Example: - -```elixir -config :pleroma, :admin_token, "somerandomtoken" -``` - -You can then do - -```sh -curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken" -``` - -## :pleroma_job_queue - -[Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs. - -Pleroma has the following queues: - -* `federator_outgoing` - Outgoing federation -* `federator_incoming` - Incoming federation -* `mailer` - Email sender, see [`Pleroma.Emails.Mailer`](#pleroma-emails-mailer) -* `transmogrifier` - Transmogrifier -* `web_push` - Web push notifications -* `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivities`](#pleromascheduledactivity) - -Example: - -```elixir -config :pleroma_job_queue, :queues, - federator_incoming: 50, - federator_outgoing: 50 -``` - -This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the `max_jobs` set to `50`. - -## Pleroma.Web.Federator.RetryQueue - -* `enabled`: If set to `true`, failed federation jobs will be retried -* `max_jobs`: The maximum amount of parallel federation jobs running at the same time. -* `initial_timeout`: The initial timeout in seconds -* `max_retries`: The maximum number of times a federation job is retried - -## Pleroma.Web.Metadata -* `providers`: a list of metadata providers to enable. Providers available: - * Pleroma.Web.Metadata.Providers.OpenGraph - * Pleroma.Web.Metadata.Providers.TwitterCard - * Pleroma.Web.Metadata.Providers.RelMe - add links from user bio with rel=me into the `
` as `` -* `unfurl_nsfw`: If set to `true` nsfw attachments will be shown in previews - -## :rich_media -* `enabled`: if enabled the instance will parse metadata from attached links to generate link previews -* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`. -* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"] -* `parsers`: list of Rich Media parsers - -## :fetch_initial_posts -* `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts -* `pages`: the amount of pages to fetch - -## :hackney_pools - -Advanced. Tweaks Hackney (http client) connections pools. - -There's three pools used: - -* `:federation` for the federation jobs. - You may want this pool max_connections to be at least equal to the number of federator jobs + retry queue jobs. -* `:media` for rich media, media proxy -* `:upload` for uploaded media (if using a remote uploader and `proxy_remote: true`) - -For each pool, the options are: - -* `max_connections` - how much connections a pool can hold -* `timeout` - retention duration for connections - -## :auto_linker - -Configuration for the `auto_linker` library: - -* `class: "auto-linker"` - specify the class to be added to the generated link. false to clear -* `rel: "noopener noreferrer"` - override the rel attribute. false to clear -* `new_window: true` - set to false to remove `target='_blank'` attribute -* `scheme: false` - Set to true to link urls with schema `http://google.com` -* `truncate: false` - Set to a number to truncate urls longer then the number. Truncated urls will end in `..` -* `strip_prefix: true` - Strip the scheme prefix -* `extra: false` - link urls with rarely used schemes (magnet, ipfs, irc, etc.) - -Example: - -```elixir -config :auto_linker, - opts: [ - scheme: true, - extra: true, - class: false, - strip_prefix: false, - new_window: false, - rel: false - ] -``` - -## Pleroma.ScheduledActivity - -* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`) -* `total_user_limit`: the number of scheduled activities a user is allowed to create in total (Default: `300`) -* `enabled`: whether scheduled activities are sent to the job queue to be executed - -## Pleroma.ActivityExpiration - -# `enabled`: whether expired activities will be sent to the job queue to be deleted - -## Pleroma.Web.Auth.Authenticator - -* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator -* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication - -## :ldap - -Use LDAP for user authentication. When a user logs in to the Pleroma -instance, the name and password will be verified by trying to authenticate -(bind) to an LDAP server. If a user exists in the LDAP directory but there -is no account with the same name yet on the Pleroma instance then a new -Pleroma account will be created with the same name as the LDAP user name. - -* `enabled`: enables LDAP authentication -* `host`: LDAP server hostname -* `port`: LDAP port, e.g. 389 or 636 -* `ssl`: true to use SSL, usually implies the port 636 -* `sslopts`: additional SSL options -* `tls`: true to start TLS, usually implies the port 389 -* `tlsopts`: additional TLS options -* `base`: LDAP base, e.g. "dc=example,dc=com" -* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base" - -## BBS / SSH access - -To enable simple command line interface accessible over ssh, add a setting like this to your configuration file: - -```exs -app_dir = File.cwd! -priv_dir = Path.join([app_dir, "priv/ssh_keys"]) - -config :esshd, - enabled: true, - priv_dir: priv_dir, - handler: "Pleroma.BBS.Handler", - port: 10_022, - password_authenticator: "Pleroma.BBS.Authenticator" -``` - -Feel free to adjust the priv_dir and port number. Then you will have to create the key for the keys (in the example `priv/ssh_keys`) and create the host keys with `ssh-keygen -m PEM -N "" -b 2048 -t rsa -f ssh_host_rsa_key`. After restarting, you should be able to connect to your Pleroma instance with `ssh username@server -p $PORT` - -## :auth - -* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator -* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication - -Authentication / authorization settings. - -* `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`. -* `oauth_consumer_template`: OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`. -* `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by `OAUTH_CONSUMER_STRATEGIES` environment variable. Each entry in this space-delimited string should be of format `` or `:` (e.g. `twitter` or `keycloak:ueberauth_keycloak_strategy` in case dependency is named differently than `ueberauth_`). - -## :email_notifications - -Email notifications settings. - - - digest - emails of "what you've missed" for users who have been - inactive for a while. - - active: globally enable or disable digest emails - - schedule: When to send digest email, in [crontab format](https://en.wikipedia.org/wiki/Cron). - "0 0 * * 0" is the default, meaning "once a week at midnight on Sunday morning" - - interval: Minimum interval between digest emails to one user - - inactivity_threshold: Minimum user inactivity threshold - -## Pleroma.Emails.UserEmail - -- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo. -- `:styling` - a map with color settings for email templates. - -## OAuth consumer mode - -OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.). -Implementation is based on Ueberauth; see the list of [available strategies](https://github.com/ueberauth/ueberauth/wiki/List-of-Strategies). - -Note: each strategy is shipped as a separate dependency; in order to get the strategies, run `OAUTH_CONSUMER_STRATEGIES="..." mix deps.get`, -e.g. `OAUTH_CONSUMER_STRATEGIES="twitter facebook google microsoft" mix deps.get`. -The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx.server` in case you enable any strategies. - -Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies. - -Note: make sure that `"SameSite=Lax"` is set in `extra_cookie_attrs` when you have this feature enabled. OAuth consumer mode will not work with `"SameSite=Strict"` - -* For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https:///oauth/twitter/callback - -* For Facebook, [register an app](https://developers.facebook.com/apps), configure callback URL to https:///oauth/facebook/callback, enable Facebook Login service at https://developers.facebook.com/apps//fb-login/settings/ - -* For Google, [register an app](https://console.developers.google.com), configure callback URL to https:///oauth/google/callback - -* For Microsoft, [register an app](https://portal.azure.com), configure callback URL to https:///oauth/microsoft/callback - -Once the app is configured on external OAuth provider side, add app's credentials and strategy-specific settings (if any — e.g. see Microsoft below) to `config/prod.secret.exs`, -per strategy's documentation (e.g. [ueberauth_twitter](https://github.com/ueberauth/ueberauth_twitter)). Example config basing on environment variables: - -```elixir -# Twitter -config :ueberauth, Ueberauth.Strategy.Twitter.OAuth, - consumer_key: System.get_env("TWITTER_CONSUMER_KEY"), - consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET") - -# Facebook -config :ueberauth, Ueberauth.Strategy.Facebook.OAuth, - client_id: System.get_env("FACEBOOK_APP_ID"), - client_secret: System.get_env("FACEBOOK_APP_SECRET"), - redirect_uri: System.get_env("FACEBOOK_REDIRECT_URI") - -# Google -config :ueberauth, Ueberauth.Strategy.Google.OAuth, - client_id: System.get_env("GOOGLE_CLIENT_ID"), - client_secret: System.get_env("GOOGLE_CLIENT_SECRET"), - redirect_uri: System.get_env("GOOGLE_REDIRECT_URI") - -# Microsoft -config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth, - client_id: System.get_env("MICROSOFT_CLIENT_ID"), - client_secret: System.get_env("MICROSOFT_CLIENT_SECRET") - -config :ueberauth, Ueberauth, - providers: [ - microsoft: {Ueberauth.Strategy.Microsoft, [callback_params: []]} - ] - -# Keycloak -# Note: make sure to add `keycloak:ueberauth_keycloak_strategy` entry to `OAUTH_CONSUMER_STRATEGIES` environment variable -keycloak_url = "https://publicly-reachable-keycloak-instance.org:8080" - -config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth, - client_id: System.get_env("KEYCLOAK_CLIENT_ID"), - client_secret: System.get_env("KEYCLOAK_CLIENT_SECRET"), - site: keycloak_url, - authorize_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/auth", - token_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/token", - userinfo_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/userinfo", - token_method: :post - -config :ueberauth, Ueberauth, - providers: [ - keycloak: {Ueberauth.Strategy.Keycloak, [uid_field: :email]} - ] -``` - -## OAuth 2.0 provider - :oauth2 - -Configure OAuth 2 provider capabilities: - -* `token_expires_in` - The lifetime in seconds of the access token. -* `issue_new_refresh_token` - Keeps old refresh token or generate new refresh token when to obtain an access token. -* `clean_expired_tokens` - Enable a background job to clean expired oauth tokens. Defaults to `false`. -* `clean_expired_tokens_interval` - Interval to run the job to clean expired tokens. Defaults to `86_400_000` (24 hours). - -## :emoji -* `shortcode_globs`: Location of custom emoji files. `*` can be used as a wildcard. Example `["/emoji/custom/**/*.png"]` -* `pack_extensions`: A list of file extensions for emojis, when no emoji.txt for a pack is present. Example `[".png", ".gif"]` -* `groups`: Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname and the value the location or array of locations. `*` can be used as a wildcard. Example `[Custom: ["/emoji/*.png", "/emoji/custom/*.png"]]` -* `default_manifest`: Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays). - -## Database options - -### RUM indexing for full text search -* `rum_enabled`: If RUM indexes should be used. Defaults to `false`. - -RUM indexes are an alternative indexing scheme that is not included in PostgreSQL by default. While they may eventually be mainlined, for now they have to be installed as a PostgreSQL extension from https://github.com/postgrespro/rum. - -Their advantage over the standard GIN indexes is that they allow efficient ordering of search results by timestamp, which makes search queries a lot faster on larger servers, by one or two orders of magnitude. They take up around 3 times as much space as GIN indexes. - -To enable them, both the `rum_enabled` flag has to be set and the following special migration has to be run: - -`mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/` - -This will probably take a long time. - -## :rate_limit - -This is an advanced feature and disabled by default. - -A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: - -* The first element: `scale` (Integer). The time scale in milliseconds. -* The second element: `limit` (Integer). How many requests to limit in the time scale provided. - -It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated. - -See [`Pleroma.Plugs.RateLimiter`](Pleroma.Plugs.RateLimiter.html) documentation for examples. - -Supported rate limiters: - -* `:search` for the search requests (account & status search etc.) -* `:app_account_creation` for registering user accounts from the same IP address -* `:relations_actions` for actions on relations with all users (follow, unfollow) -* `:relation_id_action` for actions on relation with a specific user (follow, unfollow) -* `:statuses_actions` for create / delete / fav / unfav / reblog / unreblog actions on any statuses -* `:status_id_action` for fav / unfav or reblog / unreblog actions on the same status by the same user - -## :web_cache_ttl - -The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration. - -Available caches: - -* `:activity_pub` - activity pub routes (except question activities). Defaults to `nil` (no expiration). -* `:activity_pub_question` - activity pub routes (question activities). Defaults to `30_000` (30 seconds). +# Configuration + +This file describe the configuration, it is recommended to edit the relevant *.secret.exs file instead of the others founds in the ``config`` directory. +If you run Pleroma with ``MIX_ENV=prod`` the file is ``prod.secret.exs``, otherwise it is ``dev.secret.exs``. + +## Pleroma.Upload +* `uploader`: Select which `Pleroma.Uploaders` to use +* `filters`: List of `Pleroma.Upload.Filter` to use. +* `link_name`: When enabled Pleroma will add a `name` parameter to the url of the upload, for example `https://instance.tld/media/corndog.png?name=corndog.png`. This is needed to provide the correct filename in Content-Disposition headers when using filters like `Pleroma.Upload.Filter.Dedupe` +* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host. +* `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it. +* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation. + +Note: `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`. + +## Pleroma.Uploaders.Local +* `uploads`: Which directory to store the user-uploads in, relative to pleroma’s working directory + +## Pleroma.Uploaders.S3 +* `bucket`: S3 bucket name +* `bucket_namespace`: S3 bucket namespace +* `public_endpoint`: S3 endpoint that the user finally accesses(ex. "https://s3.dualstack.ap-northeast-1.amazonaws.com") +* `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc. +For example, when using CDN to S3 virtual host format, set "". +At this time, write CNAME to CDN in public_endpoint. + +## Pleroma.Upload.Filter.Mogrify + +* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`. + +## Pleroma.Upload.Filter.Dedupe + +No specific configuration. + +## Pleroma.Upload.Filter.AnonymizeFilename + +This filter replaces the filename (not the path) of an upload. For complete obfuscation, add +`Pleroma.Upload.Filter.Dedupe` before AnonymizeFilename. + +* `text`: Text to replace filenames in links. If empty, `{random}.extension` will be used. You can get the original filename extension by using `{extension}`, for example `custom-file-name.{extension}`. + +## Pleroma.Emails.Mailer +* `adapter`: one of the mail adapters listed in [Swoosh readme](https://github.com/swoosh/swoosh#adapters), or `Swoosh.Adapters.Local` for in-memory mailbox. +* `api_key` / `password` and / or other adapter-specific settings, per the above documentation. +* `enabled`: Allows enable/disable send emails. Default: `false`. + +An example for Sendgrid adapter: + +```elixir +config :pleroma, Pleroma.Emails.Mailer, + adapter: Swoosh.Adapters.Sendgrid, + api_key: "YOUR_API_KEY" +``` + +An example for SMTP adapter: + +```elixir +config :pleroma, Pleroma.Emails.Mailer, + adapter: Swoosh.Adapters.SMTP, + relay: "smtp.gmail.com", + username: "YOUR_USERNAME@gmail.com", + password: "YOUR_SMTP_PASSWORD", + port: 465, + ssl: true, + tls: :always, + auth: :always +``` + +## :uri_schemes +* `valid_schemes`: List of the scheme part that is considered valid to be an URL + +## :instance +* `name`: The instance’s name +* `email`: Email used to reach an Administrator/Moderator of the instance +* `notify_email`: Email used for notifications. +* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance`` +* `limit`: Posts character limit (CW/Subject included in the counter) +* `remote_limit`: Hard character limit beyond which remote posts will be dropped. +* `upload_limit`: File size limit of uploads (except for avatar, background, banner) +* `avatar_upload_limit`: File size limit of user’s profile avatars +* `background_upload_limit`: File size limit of user’s profile backgrounds +* `banner_upload_limit`: File size limit of user’s profile banners +* `poll_limits`: A map with poll limits for **local** polls + * `max_options`: Maximum number of options + * `max_option_chars`: Maximum number of characters per option + * `min_expiration`: Minimum expiration time (in seconds) + * `max_expiration`: Maximum expiration time (in seconds) +* `registrations_open`: Enable registrations for anyone, invitations can be enabled when false. +* `invites_enabled`: Enable user invitations for admins (depends on `registrations_open: false`). +* `account_activation_required`: Require users to confirm their emails before signing in. +* `federating`: Enable federation with other instances +* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes. +* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it. +* `allow_relay`: Enable Pleroma’s Relay, which makes it possible to follow a whole instance +* `rewrite_policy`: Message Rewrite Policy, either one or a list. Here are the ones available by default: + * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default) + * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production + * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See ``:mrf_simple`` section) + * `Pleroma.Web.ActivityPub.MRF.TagPolicy`: Applies policies to individual users based on tags, which can be set using pleroma-fe/admin-fe/any other app that supports Pleroma Admin API. For example it allows marking posts from individual users nsfw (sensitive) + * `Pleroma.Web.ActivityPub.MRF.SubchainPolicy`: Selectively runs other MRF policies when messages match (see ``:mrf_subchain`` section) + * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See ``:mrf_rejectnonpublic`` section) + * `Pleroma.Web.ActivityPub.MRF.EnsureRePrepended`: Rewrites posts to ensure that replies to posts with subjects do not have an identical subject and instead begin with re:. + * `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links. + * `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed. + * `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (see `:mrf_mention` section) + * `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (see `:mrf_vocabulary` section) +* `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. +* `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send. +* `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json`` +* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML) +* `mrf_transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). +* `mrf_transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. +* `scope_copy`: Copy the scope (private/unlisted/public) in replies to posts by default. +* `subject_line_behavior`: Allows changing the default behaviour of subject lines in replies. Valid values: + * "email": Copy and preprend re:, as in email. + * "masto": Copy verbatim, as in Mastodon. + * "noop": Don't copy the subject. +* `always_show_subject_input`: When set to false, auto-hide the subject field when it's empty. +* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with + older software for theses nicknames. +* `max_pinned_statuses`: The maximum number of pinned statuses. `0` will disable the feature. +* `autofollowed_nicknames`: Set to nicknames of (local) users that every new user should automatically follow. +* `no_attachment_links`: Set to true to disable automatically adding attachment link text to statuses +* `welcome_message`: A message that will be send to a newly registered users as a direct message. +* `welcome_user_nickname`: The nickname of the local user that sends the welcome message. +* `max_report_comment_size`: The maximum size of the report comment (Default: `1000`) +* `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). Default: `false`. +* `healthcheck`: If set to true, system data will be shown on ``/api/pleroma/healthcheck``. +* `remote_post_retention_days`: The default amount of days to retain remote posts when pruning the database. +* `user_bio_length`: A user bio maximum length (default: `5000`) +* `user_name_length`: A user name maximum length (default: `100`) +* `skip_thread_containment`: Skip filter out broken threads. The default is `false`. +* `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. +* `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. +* `max_account_fields`: The maximum number of custom fields in the user profile (default: `10`) +* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `20`) +* `account_field_name_length`: An account field name maximum length (default: `512`) +* `account_field_value_length`: An account field value maximum length (default: `512`) +* `external_user_synchronization`: Enabling following/followers counters synchronization for external users. + + + +## :logger +* `backends`: `:console` is used to send logs to stdout, `{ExSyslogger, :ex_syslogger}` to log to syslog, and `Quack.Logger` to log to Slack + +An example to enable ONLY ExSyslogger (f/ex in ``prod.secret.exs``) with info and debug suppressed: +```elixir +config :logger, + backends: [{ExSyslogger, :ex_syslogger}] + +config :logger, :ex_syslogger, + level: :warn +``` + +Another example, keeping console output and adding the pid to syslog output: +```elixir +config :logger, + backends: [:console, {ExSyslogger, :ex_syslogger}] + +config :logger, :ex_syslogger, + level: :warn, + option: [:pid, :ndelay] +``` + +See: [logger’s documentation](https://hexdocs.pm/logger/Logger.html) and [ex_syslogger’s documentation](https://hexdocs.pm/ex_syslogger/) + +An example of logging info to local syslog, but warn to a Slack channel: +```elixir +config :logger, + backends: [ {ExSyslogger, :ex_syslogger}, Quack.Logger ], + level: :info + +config :logger, :ex_syslogger, + level: :info, + ident: "pleroma", + format: "$metadata[$level] $message" + +config :quack, + level: :warn, + meta: [:all], + webhook_url: "https://hooks.slack.com/services/YOUR-API-KEY-HERE" +``` + +See the [Quack Github](https://github.com/azohra/quack) for more details + +## :frontend_configurations + +This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` and `masto_fe` are configured. + +Frontends can access these settings at `/api/pleroma/frontend_configurations` + +To add your own configuration for PleromaFE, use it like this: + +```elixir +config :pleroma, :frontend_configurations, + pleroma_fe: %{ + theme: "pleroma-dark", + # ... see /priv/static/static/config.json for the available keys. +}, + masto_fe: %{ + showInstanceSpecificPanel: true + } +``` + +These settings **need to be complete**, they will override the defaults. + +NOTE: for versions < 1.0, you need to set [`:fe`](#fe) to false, as shown a few lines below. + +## :fe +__THIS IS DEPRECATED__ + +If you are using this method, please change it to the [`frontend_configurations`](#frontend_configurations) method. +Please **set this option to false** in your config like this: + +```elixir +config :pleroma, :fe, false +``` + +This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:instance`` is set to false. + +* `theme`: Which theme to use, they are defined in ``styles.json`` +* `logo`: URL of the logo, defaults to Pleroma’s logo +* `logo_mask`: Whether to use only the logo's shape as a mask (true) or as a regular image (false) +* `logo_margin`: What margin to use around the logo +* `background`: URL of the background, unless viewing a user profile with a background that is set +* `redirect_root_no_login`: relative URL which indicates where to redirect when a user isn’t logged in. +* `redirect_root_login`: relative URL which indicates where to redirect when a user is logged in. +* `show_instance_panel`: Whenether to show the instance’s specific panel. +* `scope_options_enabled`: Enable setting an notice visibility and subject/CW when posting +* `formatting_options_enabled`: Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to ``:instance, allowed_post_formats`` +* `collapse_message_with_subjects`: When a message has a subject(aka Content Warning), collapse it by default +* `hide_post_stats`: Hide notices statistics(repeats, favorites, …) +* `hide_user_stats`: Hide profile statistics(posts, posts per day, followers, followings, …) + +## :assets + +This section configures assets to be used with various frontends. Currently the only option +relates to mascots on the mastodon frontend + +* `mascots`: KeywordList of mascots, each element __MUST__ contain both a `url` and a + `mime_type` key. +* `default_mascot`: An element from `mascots` - This will be used as the default mascot + on MastoFE (default: `:pleroma_fox_tan`) + +## :mrf_simple +* `media_removal`: List of instances to remove medias from +* `media_nsfw`: List of instances to put medias as NSFW(sensitive) from +* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline +* `reject`: List of instances to reject any activities from +* `accept`: List of instances to accept any activities from +* `report_removal`: List of instances to reject reports from +* `avatar_removal`: List of instances to strip avatars from +* `banner_removal`: List of instances to strip banners from + +## :mrf_subchain +This policy processes messages through an alternate pipeline when a given message matches certain criteria. +All criteria are configured as a map of regular expressions to lists of policy modules. + +* `match_actor`: Matches a series of regular expressions against the actor field. + +Example: + +``` +config :pleroma, :mrf_subchain, + match_actor: %{ + ~r/https:\/\/example.com/s => [Pleroma.Web.ActivityPub.MRF.DropPolicy] + } +``` + +## :mrf_rejectnonpublic +* `allow_followersonly`: whether to allow followers-only posts +* `allow_direct`: whether to allow direct messages + +## :mrf_hellthread +* `delist_threshold`: Number of mentioned users after which the message gets delisted (the message can still be seen, but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable. +* `reject_threshold`: Number of mentioned users after which the messaged gets rejected. Set to 0 to disable. + +## :mrf_keyword +* `reject`: A list of patterns which result in message being rejected, each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) +* `federated_timeline_removal`: A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) +* `replace`: A list of tuples containing `{pattern, replacement}`, `pattern` can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html) + +## :mrf_mention +* `actors`: A list of actors, for which to drop any posts mentioning. + +## :mrf_vocabulary +* `accept`: A list of ActivityStreams terms to accept. If empty, all supported messages are accepted. +* `reject`: A list of ActivityStreams terms to reject. If empty, no messages are rejected. + +## :media_proxy +* `enabled`: Enables proxying of remote media to the instance’s proxy +* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts. +* `proxy_opts`: All options defined in `Pleroma.ReverseProxy` documentation, defaults to `[max_body_length: (25*1_048_576)]`. +* `whitelist`: List of domains to bypass the mediaproxy + +## :gopher +* `enabled`: Enables the gopher interface +* `ip`: IP address to bind to +* `port`: Port to bind to +* `dstport`: Port advertised in urls (optional, defaults to `port`) + +## Pleroma.Web.Endpoint +`Phoenix` endpoint configuration, all configuration options can be viewed [here](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#module-dynamic-configuration), only common options are listed here +* `http` - a list containing http protocol configuration, all configuration options can be viewed [here](https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html#module-options), only common options are listed here. For deployment using docker, you need to set this to `[ip: {0,0,0,0}, port: 4000]` to make pleroma accessible from other containers (such as your nginx server). + - `ip` - a tuple consisting of 4 integers + - `port` +* `url` - a list containing the configuration for generating urls, accepts + - `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`) + - `scheme` - e.g `http`, `https` + - `port` + - `path` +* `extra_cookie_attrs` - a list of `Key=Value` strings to be added as non-standard cookie attributes. Defaults to `["SameSite=Lax"]`. See the [SameSite article](https://www.owasp.org/index.php/SameSite) on OWASP for more info. + + + +**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need + +Example: +```elixir +config :pleroma, Pleroma.Web.Endpoint, + url: [host: "example.com", port: 2020, scheme: "https"], + http: [ + # start copied from config.exs + dispatch: [ + {:_, + [ + {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, + {"/websocket", Phoenix.Endpoint.CowboyWebSocket, + {Phoenix.Transports.WebSocket, + {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}}, + {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} + ]} + # end copied from config.exs + ], + port: 8080, + ip: {127, 0, 0, 1} + ] +``` + +This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020` + +## :activitypub +* ``unfollow_blocked``: Whether blocks result in people getting unfollowed +* ``outgoing_blocks``: Whether to federate blocks to other instances +* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question +* ``sign_object_fetches``: Sign object fetches with HTTP signatures + +## :http_security +* ``enabled``: Whether the managed content security policy is enabled +* ``sts``: Whether to additionally send a `Strict-Transport-Security` header +* ``sts_max_age``: The maximum age for the `Strict-Transport-Security` header if sent +* ``ct_max_age``: The maximum age for the `Expect-CT` header if sent +* ``referrer_policy``: The referrer policy to use, either `"same-origin"` or `"no-referrer"` +* ``report_uri``: Adds the specified url to `report-uri` and `report-to` group in CSP header. + +## :mrf_user_allowlist + +The keys in this section are the domain names that the policy should apply to. +Each key should be assigned a list of users that should be allowed through by +their ActivityPub ID. + +An example: + +```elixir +config :pleroma, :mrf_user_allowlist, + "example.org": ["https://example.org/users/admin"] +``` + +## :web_push_encryption, :vapid_details + +Web Push Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it. + +* ``subject``: a mailto link for the administrative contact. It’s best if this email is not a personal email address, but rather a group email so that if a person leaves an organization, is unavailable for an extended period, or otherwise can’t respond, someone else on the list can. +* ``public_key``: VAPID public key +* ``private_key``: VAPID private key + +## Pleroma.Captcha +* `enabled`: Whether the captcha should be shown on registration +* `method`: The method/service to use for captcha +* `seconds_valid`: The time in seconds for which the captcha is valid + +### Pleroma.Captcha.Kocaptcha +Kocaptcha is a very simple captcha service with a single API endpoint, +the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint +`https://captcha.kotobank.ch` is hosted by the developer. + +* `endpoint`: the kocaptcha endpoint to use + +## :admin_token + +Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the 'admin_token' parameter. Example: + +```elixir +config :pleroma, :admin_token, "somerandomtoken" +``` + +You can then do + +```sh +curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken" +``` + +## Oban + +[Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration. + +Configuration options described in [Oban readme](https://github.com/sorentwo/oban#usage): +* `repo` - app's Ecto repo (`Pleroma.Repo`) +* `verbose` - logs verbosity +* `prune` - non-retryable jobs [pruning settings](https://github.com/sorentwo/oban#pruning) (`:disabled` / `{:maxlen, value}` / `{:maxage, value}`) +* `queues` - job queues (see below) + +Pleroma has the following queues: + +* `activity_expiration` - Activity expiration +* `federator_outgoing` - Outgoing federation +* `federator_incoming` - Incoming federation +* `mailer` - Email sender, see [`Pleroma.Emails.Mailer`](#pleromaemailsmailer) +* `transmogrifier` - Transmogrifier +* `web_push` - Web push notifications +* `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivity`](#pleromascheduledactivity) + +Example: + +```elixir +config :pleroma, Oban, + repo: Pleroma.Repo, + verbose: false, + prune: {:maxlen, 1500}, + queues: [ + federator_incoming: 50, + federator_outgoing: 50 + ] +``` + +This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the number of max concurrent jobs set to `50`. + +### Migrating `pleroma_job_queue` settings + +`config :pleroma_job_queue, :queues` is replaced by `config :pleroma, Oban, :queues` and uses the same format (keys are queues' names, values are max concurrent jobs numbers). + +### Note on running with PostgreSQL in silent mode + +If you are running PostgreSQL in [`silent_mode`](https://postgresqlco.nf/en/doc/param/silent_mode?version=9.1), it's advised to set [`log_destination`](https://postgresqlco.nf/en/doc/param/log_destination?version=9.1) to `syslog`, +otherwise `postmaster.log` file may grow because of "you don't own a lock of type ShareLock" warnings (see https://github.com/sorentwo/oban/issues/52). + +## :workers + +Includes custom worker options not interpretable directly by `Oban`. + +* `retries` — keyword lists where keys are `Oban` queues (see above) and values are numbers of max attempts for failed jobs. + +Example: + +```elixir +config :pleroma, :workers, + retries: [ + federator_incoming: 5, + federator_outgoing: 5 + ] +``` + +### Migrating `Pleroma.Web.Federator.RetryQueue` settings + +* `max_retries` is replaced with `config :pleroma, :workers, retries: [federator_outgoing: 5]` +* `enabled: false` corresponds to `config :pleroma, :workers, retries: [federator_outgoing: 1]` +* deprecated options: `max_jobs`, `initial_timeout` + +## Pleroma.Web.Metadata +* `providers`: a list of metadata providers to enable. Providers available: + * Pleroma.Web.Metadata.Providers.OpenGraph + * Pleroma.Web.Metadata.Providers.TwitterCard + * Pleroma.Web.Metadata.Providers.RelMe - add links from user bio with rel=me into the `
` as `` +* `unfurl_nsfw`: If set to `true` nsfw attachments will be shown in previews + +## :rich_media +* `enabled`: if enabled the instance will parse metadata from attached links to generate link previews +* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`. +* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"] +* `parsers`: list of Rich Media parsers + +## :fetch_initial_posts +* `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts +* `pages`: the amount of pages to fetch + +## :hackney_pools + +Advanced. Tweaks Hackney (http client) connections pools. + +There's three pools used: + +* `:federation` for the federation jobs. + You may want this pool max_connections to be at least equal to the number of federator jobs + retry queue jobs. +* `:media` for rich media, media proxy +* `:upload` for uploaded media (if using a remote uploader and `proxy_remote: true`) + +For each pool, the options are: + +* `max_connections` - how much connections a pool can hold +* `timeout` - retention duration for connections + +## :auto_linker + +Configuration for the `auto_linker` library: + +* `class: "auto-linker"` - specify the class to be added to the generated link. false to clear +* `rel: "noopener noreferrer"` - override the rel attribute. false to clear +* `new_window: true` - set to false to remove `target='_blank'` attribute +* `scheme: false` - Set to true to link urls with schema `http://google.com` +* `truncate: false` - Set to a number to truncate urls longer then the number. Truncated urls will end in `..` +* `strip_prefix: true` - Strip the scheme prefix +* `extra: false` - link urls with rarely used schemes (magnet, ipfs, irc, etc.) + +Example: + +```elixir +config :auto_linker, + opts: [ + scheme: true, + extra: true, + class: false, + strip_prefix: false, + new_window: false, + rel: false + ] +``` + +## Pleroma.Scheduler + +Configuration for [Quantum](https://github.com/quantum-elixir/quantum-core) jobs scheduler. + +See [Quantum readme](https://github.com/quantum-elixir/quantum-core#usage) for the list of supported options. + +Example: + +```elixir +config :pleroma, Pleroma.Scheduler, + global: true, + overlap: true, + timezone: :utc, + jobs: [{"0 */6 * * * *", {Pleroma.Web.Websub, :refresh_subscriptions, []}}] +``` + +The above example defines a single job which invokes `Pleroma.Web.Websub.refresh_subscriptions()` every 6 hours ("0 */6 * * * *", [crontab format](https://en.wikipedia.org/wiki/Cron)). + +## Pleroma.ScheduledActivity + +* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`) +* `total_user_limit`: the number of scheduled activities a user is allowed to create in total (Default: `300`) +* `enabled`: whether scheduled activities are sent to the job queue to be executed + +## Pleroma.ActivityExpiration + +# `enabled`: whether expired activities will be sent to the job queue to be deleted + +## Pleroma.Web.Auth.Authenticator + +* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator +* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication + +## :ldap + +Use LDAP for user authentication. When a user logs in to the Pleroma +instance, the name and password will be verified by trying to authenticate +(bind) to an LDAP server. If a user exists in the LDAP directory but there +is no account with the same name yet on the Pleroma instance then a new +Pleroma account will be created with the same name as the LDAP user name. + +* `enabled`: enables LDAP authentication +* `host`: LDAP server hostname +* `port`: LDAP port, e.g. 389 or 636 +* `ssl`: true to use SSL, usually implies the port 636 +* `sslopts`: additional SSL options +* `tls`: true to start TLS, usually implies the port 389 +* `tlsopts`: additional TLS options +* `base`: LDAP base, e.g. "dc=example,dc=com" +* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base" + +## BBS / SSH access + +To enable simple command line interface accessible over ssh, add a setting like this to your configuration file: + +```exs +app_dir = File.cwd! +priv_dir = Path.join([app_dir, "priv/ssh_keys"]) + +config :esshd, + enabled: true, + priv_dir: priv_dir, + handler: "Pleroma.BBS.Handler", + port: 10_022, + password_authenticator: "Pleroma.BBS.Authenticator" +``` + +Feel free to adjust the priv_dir and port number. Then you will have to create the key for the keys (in the example `priv/ssh_keys`) and create the host keys with `ssh-keygen -m PEM -N "" -b 2048 -t rsa -f ssh_host_rsa_key`. After restarting, you should be able to connect to your Pleroma instance with `ssh username@server -p $PORT` + +## :auth + +* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator +* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication + +Authentication / authorization settings. + +* `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`. +* `oauth_consumer_template`: OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`. +* `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by `OAUTH_CONSUMER_STRATEGIES` environment variable. Each entry in this space-delimited string should be of format `` or `:` (e.g. `twitter` or `keycloak:ueberauth_keycloak_strategy` in case dependency is named differently than `ueberauth_`). + +## :email_notifications + +Email notifications settings. + + - digest - emails of "what you've missed" for users who have been + inactive for a while. + - active: globally enable or disable digest emails + - schedule: When to send digest email, in [crontab format](https://en.wikipedia.org/wiki/Cron). + "0 0 * * 0" is the default, meaning "once a week at midnight on Sunday morning" + - interval: Minimum interval between digest emails to one user + - inactivity_threshold: Minimum user inactivity threshold + +## Pleroma.Emails.UserEmail + +- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo. +- `:styling` - a map with color settings for email templates. + +## OAuth consumer mode + +OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.). +Implementation is based on Ueberauth; see the list of [available strategies](https://github.com/ueberauth/ueberauth/wiki/List-of-Strategies). + +Note: each strategy is shipped as a separate dependency; in order to get the strategies, run `OAUTH_CONSUMER_STRATEGIES="..." mix deps.get`, +e.g. `OAUTH_CONSUMER_STRATEGIES="twitter facebook google microsoft" mix deps.get`. +The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx.server` in case you enable any strategies. + +Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies. + +Note: make sure that `"SameSite=Lax"` is set in `extra_cookie_attrs` when you have this feature enabled. OAuth consumer mode will not work with `"SameSite=Strict"` + +* For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https:///oauth/twitter/callback + +* For Facebook, [register an app](https://developers.facebook.com/apps), configure callback URL to https:///oauth/facebook/callback, enable Facebook Login service at https://developers.facebook.com/apps//fb-login/settings/ + +* For Google, [register an app](https://console.developers.google.com), configure callback URL to https:///oauth/google/callback + +* For Microsoft, [register an app](https://portal.azure.com), configure callback URL to https:///oauth/microsoft/callback + +Once the app is configured on external OAuth provider side, add app's credentials and strategy-specific settings (if any — e.g. see Microsoft below) to `config/prod.secret.exs`, +per strategy's documentation (e.g. [ueberauth_twitter](https://github.com/ueberauth/ueberauth_twitter)). Example config basing on environment variables: + +```elixir +# Twitter +config :ueberauth, Ueberauth.Strategy.Twitter.OAuth, + consumer_key: System.get_env("TWITTER_CONSUMER_KEY"), + consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET") + +# Facebook +config :ueberauth, Ueberauth.Strategy.Facebook.OAuth, + client_id: System.get_env("FACEBOOK_APP_ID"), + client_secret: System.get_env("FACEBOOK_APP_SECRET"), + redirect_uri: System.get_env("FACEBOOK_REDIRECT_URI") + +# Google +config :ueberauth, Ueberauth.Strategy.Google.OAuth, + client_id: System.get_env("GOOGLE_CLIENT_ID"), + client_secret: System.get_env("GOOGLE_CLIENT_SECRET"), + redirect_uri: System.get_env("GOOGLE_REDIRECT_URI") + +# Microsoft +config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth, + client_id: System.get_env("MICROSOFT_CLIENT_ID"), + client_secret: System.get_env("MICROSOFT_CLIENT_SECRET") + +config :ueberauth, Ueberauth, + providers: [ + microsoft: {Ueberauth.Strategy.Microsoft, [callback_params: []]} + ] + +# Keycloak +# Note: make sure to add `keycloak:ueberauth_keycloak_strategy` entry to `OAUTH_CONSUMER_STRATEGIES` environment variable +keycloak_url = "https://publicly-reachable-keycloak-instance.org:8080" + +config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth, + client_id: System.get_env("KEYCLOAK_CLIENT_ID"), + client_secret: System.get_env("KEYCLOAK_CLIENT_SECRET"), + site: keycloak_url, + authorize_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/auth", + token_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/token", + userinfo_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/userinfo", + token_method: :post + +config :ueberauth, Ueberauth, + providers: [ + keycloak: {Ueberauth.Strategy.Keycloak, [uid_field: :email]} + ] +``` + +## OAuth 2.0 provider - :oauth2 + +Configure OAuth 2 provider capabilities: + +* `token_expires_in` - The lifetime in seconds of the access token. +* `issue_new_refresh_token` - Keeps old refresh token or generate new refresh token when to obtain an access token. +* `clean_expired_tokens` - Enable a background job to clean expired oauth tokens. Defaults to `false`. +* `clean_expired_tokens_interval` - Interval to run the job to clean expired tokens. Defaults to `86_400_000` (24 hours). + +## :emoji +* `shortcode_globs`: Location of custom emoji files. `*` can be used as a wildcard. Example `["/emoji/custom/**/*.png"]` +* `pack_extensions`: A list of file extensions for emojis, when no emoji.txt for a pack is present. Example `[".png", ".gif"]` +* `groups`: Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname and the value the location or array of locations. `*` can be used as a wildcard. Example `[Custom: ["/emoji/*.png", "/emoji/custom/*.png"]]` +* `default_manifest`: Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays). + +## Database options + +### RUM indexing for full text search +* `rum_enabled`: If RUM indexes should be used. Defaults to `false`. + +RUM indexes are an alternative indexing scheme that is not included in PostgreSQL by default. While they may eventually be mainlined, for now they have to be installed as a PostgreSQL extension from https://github.com/postgrespro/rum. + +Their advantage over the standard GIN indexes is that they allow efficient ordering of search results by timestamp, which makes search queries a lot faster on larger servers, by one or two orders of magnitude. They take up around 3 times as much space as GIN indexes. + +To enable them, both the `rum_enabled` flag has to be set and the following special migration has to be run: + +`mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/` + +This will probably take a long time. + +## :rate_limit + +This is an advanced feature and disabled by default. + +A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: + +* The first element: `scale` (Integer). The time scale in milliseconds. +* The second element: `limit` (Integer). How many requests to limit in the time scale provided. + +It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated. + +See [`Pleroma.Plugs.RateLimiter`](Pleroma.Plugs.RateLimiter.html) documentation for examples. + +Supported rate limiters: + +* `:search` for the search requests (account & status search etc.) +* `:app_account_creation` for registering user accounts from the same IP address +* `:relations_actions` for actions on relations with all users (follow, unfollow) +* `:relation_id_action` for actions on relation with a specific user (follow, unfollow) +* `:statuses_actions` for create / delete / fav / unfav / reblog / unreblog actions on any statuses +* `:status_id_action` for fav / unfav or reblog / unreblog actions on the same status by the same user + +## :web_cache_ttl + +The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration. + +Available caches: + +* `:activity_pub` - activity pub routes (except question activities). Defaults to `nil` (no expiration). +* `:activity_pub_question` - activity pub routes (question activities). Defaults to `30_000` (30 seconds). From b4cf74c1067b866574a63fbd25ccb12cc1fed619 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Sun, 15 Sep 2019 14:53:58 +0300 Subject: [PATCH 075/272] added prepare html for RichMedia.Parser --- lib/pleroma/web/rich_media/parser.ex | 6 +++++- mix.exs | 2 +- mix.lock | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex index f5f9e358c..c06b0a0f2 100644 --- a/lib/pleroma/web/rich_media/parser.ex +++ b/lib/pleroma/web/rich_media/parser.ex @@ -81,6 +81,7 @@ defp parse_url(url) do {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options) html + |> parse_html |> maybe_parse() |> Map.put(:url, url) |> clean_parsed_data() @@ -91,6 +92,8 @@ defp parse_url(url) do end end + defp parse_html(html), do: Floki.parse(html) + defp maybe_parse(html) do Enum.reduce_while(parsers(), %{}, fn parser, acc -> case parser.parse(html, acc) do @@ -100,7 +103,8 @@ defp maybe_parse(html) do end) end - defp check_parsed_data(%{title: title} = data) when is_binary(title) and byte_size(title) > 0 do + defp check_parsed_data(%{title: title} = data) + when is_binary(title) and byte_size(title) > 0 do {:ok, data} end diff --git a/mix.exs b/mix.exs index dfa530358..6f952fa12 100644 --- a/mix.exs +++ b/mix.exs @@ -131,7 +131,7 @@ defp deps do {:phoenix_swoosh, "~> 0.2"}, {:gen_smtp, "~> 0.13"}, {:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test}, - {:floki, "~> 0.20.0"}, + {:floki, "~> 0.23.0"}, {:ex_syslogger, github: "slashmili/ex_syslogger", tag: "1.4.0"}, {:timex, "~> 3.5"}, {:ueberauth, "~> 0.4"}, diff --git a/mix.lock b/mix.lock index 5762dae4f..2bce00dea 100644 --- a/mix.lock +++ b/mix.lock @@ -34,7 +34,7 @@ "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"}, "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]}, "excoveralls": {:hex, :excoveralls, "0.11.1", "dd677fbdd49114fdbdbf445540ec735808250d56b011077798316505064edb2c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, - "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, + "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"}, "gen_smtp": {:hex, :gen_smtp, "0.14.0", "39846a03522456077c6429b4badfd1d55e5e7d0fdfb65e935b7c5e38549d9202", [:rebar3], [], "hexpm"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"}, "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, From 43f17c2e67cfb85ae469eee39b526a5baf7c7408 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 12 Sep 2019 19:04:55 +0700 Subject: [PATCH 076/272] Restore tests for `change_password` and `delete_account` --- test/web/twitter_api/util_controller_test.exs | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 0a2a48fb7..56e318182 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -775,4 +775,109 @@ test "with credentials, valid password and valid email", %{ assert json_response(conn, 200) == %{"status" => "success"} end end + + describe "POST /api/pleroma/change_password" do + setup [:valid_user] + + test "without credentials", %{conn: conn} do + conn = post(conn, "/api/pleroma/change_password") + assert json_response(conn, 403) == %{"error" => "Invalid credentials."} + end + + test "with credentials and invalid password", %{conn: conn, user: current_user} do + conn = + conn + |> with_credentials(current_user.nickname, "test") + |> post("/api/pleroma/change_password", %{ + "password" => "hi", + "new_password" => "newpass", + "new_password_confirmation" => "newpass" + }) + + assert json_response(conn, 200) == %{"error" => "Invalid password."} + end + + test "with credentials, valid password and new password and confirmation not matching", %{ + conn: conn, + user: current_user + } do + conn = + conn + |> with_credentials(current_user.nickname, "test") + |> post("/api/pleroma/change_password", %{ + "password" => "test", + "new_password" => "newpass", + "new_password_confirmation" => "notnewpass" + }) + + assert json_response(conn, 200) == %{ + "error" => "New password does not match confirmation." + } + end + + test "with credentials, valid password and invalid new password", %{ + conn: conn, + user: current_user + } do + conn = + conn + |> with_credentials(current_user.nickname, "test") + |> post("/api/pleroma/change_password", %{ + "password" => "test", + "new_password" => "", + "new_password_confirmation" => "" + }) + + assert json_response(conn, 200) == %{ + "error" => "New password can't be blank." + } + end + + test "with credentials, valid password and matching new password and confirmation", %{ + conn: conn, + user: current_user + } do + conn = + conn + |> with_credentials(current_user.nickname, "test") + |> post("/api/pleroma/change_password", %{ + "password" => "test", + "new_password" => "newpass", + "new_password_confirmation" => "newpass" + }) + + assert json_response(conn, 200) == %{"status" => "success"} + fetched_user = User.get_cached_by_id(current_user.id) + assert Comeonin.Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true + end + end + + describe "POST /api/pleroma/delete_account" do + setup [:valid_user] + + test "without credentials", %{conn: conn} do + conn = post(conn, "/api/pleroma/delete_account") + assert json_response(conn, 403) == %{"error" => "Invalid credentials."} + end + + test "with credentials and invalid password", %{conn: conn, user: current_user} do + conn = + conn + |> with_credentials(current_user.nickname, "test") + |> post("/api/pleroma/delete_account", %{"password" => "hi"}) + + assert json_response(conn, 200) == %{"error" => "Invalid password."} + end + + test "with credentials and valid password", %{conn: conn, user: current_user} do + conn = + conn + |> with_credentials(current_user.nickname, "test") + |> post("/api/pleroma/delete_account", %{"password" => "test"}) + + assert json_response(conn, 200) == %{"status" => "success"} + # Wait a second for the started task to end + :timer.sleep(1000) + end + end end From ca88e37a8f3b0b52771f94df676e26471fb44019 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 16 Sep 2019 12:55:05 +0700 Subject: [PATCH 077/272] Fix a race condition in tests --- test/web/mastodon_api/mastodon_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 9c5322ccb..fb04748bb 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -752,7 +752,7 @@ test "get statuses by IDs", %{conn: conn} do query_string = "ids[]=#{id1}&ids[]=#{id2}" conn = get(conn, "/api/v1/statuses/?#{query_string}") - assert [%{"id" => ^id1}, %{"id" => ^id2}] = json_response(conn, :ok) + assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"]) end describe "deleting a status" do From aab264db82054df470075c65ca25c42bbcc5d7a8 Mon Sep 17 00:00:00 2001 From: Steven Fuchs Date: Mon, 16 Sep 2019 07:44:03 +0000 Subject: [PATCH 078/272] Streamer refactoring --- .gitignore | 4 + config/config.exs | 4 + lib/pleroma/activity/ir/topics.ex | 63 ++++ lib/pleroma/application.ex | 2 +- lib/pleroma/notification.ex | 6 +- lib/pleroma/web/activity_pub/activity_pub.ex | 48 +-- .../web/mastodon_api/websocket_handler.ex | 7 +- lib/pleroma/web/streamer.ex | 318 ------------------ lib/pleroma/web/streamer/ping.ex | 33 ++ lib/pleroma/web/streamer/state.ex | 68 ++++ lib/pleroma/web/streamer/streamer.ex | 55 +++ lib/pleroma/web/streamer/streamer_socket.ex | 31 ++ lib/pleroma/web/streamer/supervisor.ex | 33 ++ lib/pleroma/web/streamer/worker.ex | 220 ++++++++++++ lib/pleroma/web/views/streamer_view.ex | 66 ++++ mix.exs | 1 + mix.lock | 1 + test/activity/ir/topics_test.exs | 141 ++++++++ test/integration/mastodon_websocket_test.exs | 16 +- test/notification_test.exs | 11 +- test/support/conn_case.ex | 4 + test/support/data_case.ex | 4 + test/web/activity_pub/activity_pub_test.exs | 4 +- test/web/streamer/ping_test.exs | 36 ++ test/web/streamer/state_test.exs | 54 +++ test/web/{ => streamer}/streamer_test.exs | 105 +++--- 26 files changed, 888 insertions(+), 447 deletions(-) create mode 100644 lib/pleroma/activity/ir/topics.ex delete mode 100644 lib/pleroma/web/streamer.ex create mode 100644 lib/pleroma/web/streamer/ping.ex create mode 100644 lib/pleroma/web/streamer/state.ex create mode 100644 lib/pleroma/web/streamer/streamer.ex create mode 100644 lib/pleroma/web/streamer/streamer_socket.ex create mode 100644 lib/pleroma/web/streamer/supervisor.ex create mode 100644 lib/pleroma/web/streamer/worker.ex create mode 100644 lib/pleroma/web/views/streamer_view.ex create mode 100644 test/activity/ir/topics_test.exs create mode 100644 test/web/streamer/ping_test.exs create mode 100644 test/web/streamer/state_test.exs rename test/web/{ => streamer}/streamer_test.exs (86%) diff --git a/.gitignore b/.gitignore index 4e71a7df0..3b0c7d361 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ docs/generated_config.md # Code test coverage /cover /Elixir.*.coverdata + +.idea +pleroma.iml + diff --git a/config/config.exs b/config/config.exs index ab6e00c98..b1b98af93 100644 --- a/config/config.exs +++ b/config/config.exs @@ -331,6 +331,10 @@ follow_handshake_timeout: 500, sign_object_fetches: true +config :pleroma, :streamer, + workers: 3, + overflow_workers: 2 + config :pleroma, :user, deny_follow_blocked: true config :pleroma, :mrf_normalize_markup, scrub_policy: Pleroma.HTML.Scrubber.Default diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex new file mode 100644 index 000000000..010897abc --- /dev/null +++ b/lib/pleroma/activity/ir/topics.ex @@ -0,0 +1,63 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Activity.Ir.Topics do + alias Pleroma.Object + alias Pleroma.Web.ActivityPub.Visibility + + def get_activity_topics(activity) do + activity + |> Object.normalize() + |> generate_topics(activity) + |> List.flatten() + end + + defp generate_topics(%{data: %{"type" => "Answer"}}, _) do + [] + end + + defp generate_topics(object, activity) do + ["user", "list"] ++ visibility_tags(object, activity) + end + + defp visibility_tags(object, activity) do + case Visibility.get_visibility(activity) do + "public" -> + if activity.local do + ["public", "public:local"] + else + ["public"] + end + |> item_creation_tags(object, activity) + + "direct" -> + ["direct"] + + _ -> + [] + end + end + + defp item_creation_tags(tags, %{data: %{"type" => "Create"}} = object, activity) do + tags ++ hashtags_to_topics(object) ++ attachment_topics(object, activity) + end + + defp item_creation_tags(tags, _, _) do + tags + end + + defp hashtags_to_topics(%{data: %{"tag" => tags}}) do + tags + |> Enum.filter(&is_bitstring(&1)) + |> Enum.map(fn tag -> "hashtag:" <> tag end) + end + + defp hashtags_to_topics(_), do: [] + + defp attachment_topics(%{data: %{"attachment" => []}}, _act), do: [] + + defp attachment_topics(_object, %{local: true}), do: ["public:media", "public:local:media"] + + defp attachment_topics(_object, _act), do: ["public:media"] +end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 49094704b..3b37ce630 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -141,7 +141,7 @@ defp oauth_cleanup_enabled?, defp streamer_child(:test), do: [] defp streamer_child(_) do - [Pleroma.Web.Streamer] + [Pleroma.Web.Streamer.supervisor()] end defp oauth_cleanup_child(true), diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index b7c880c51..8012389ac 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -210,8 +210,10 @@ def create_notification(%Activity{} = activity, %User{} = user) do unless skip?(activity, user) do notification = %Notification{user_id: user.id, activity: activity} {:ok, notification} = Repo.insert(notification) - Streamer.stream("user", notification) - Streamer.stream("user:notification", notification) + + ["user", "user:notification"] + |> Streamer.stream(notification) + Push.send(notification) notification end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 41f6a0f1f..bc5ae7fbf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity + alias Pleroma.Activity.Ir.Topics alias Pleroma.Config alias Pleroma.Conversation alias Pleroma.Notification @@ -16,6 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.Streamer alias Pleroma.Web.WebFinger alias Pleroma.Workers.BackgroundWorker @@ -187,9 +189,7 @@ def stream_out_participations(participations) do participations |> Repo.preload(:user) - Enum.each(participations, fn participation -> - Pleroma.Web.Streamer.stream("participation", participation) - end) + Streamer.stream("participation", participations) end def stream_out_participations(%Object{data: %{"context" => context}}, user) do @@ -208,41 +208,15 @@ def stream_out_participations(%Object{data: %{"context" => context}}, user) do def stream_out_participations(_, _), do: :noop - def stream_out(activity) do - if activity.data["type"] in ["Create", "Announce", "Delete"] do - object = Object.normalize(activity) - # Do not stream out poll replies - unless object.data["type"] == "Answer" do - Pleroma.Web.Streamer.stream("user", activity) - Pleroma.Web.Streamer.stream("list", activity) + def stream_out(%Activity{data: %{"type" => data_type}} = activity) + when data_type in ["Create", "Announce", "Delete"] do + activity + |> Topics.get_activity_topics() + |> Streamer.stream(activity) + end - if get_visibility(activity) == "public" do - Pleroma.Web.Streamer.stream("public", activity) - - if activity.local do - Pleroma.Web.Streamer.stream("public:local", activity) - end - - if activity.data["type"] in ["Create"] do - object.data - |> Map.get("tag", []) - |> Enum.filter(fn tag -> is_bitstring(tag) end) - |> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end) - - if object.data["attachment"] != [] do - Pleroma.Web.Streamer.stream("public:media", activity) - - if activity.local do - Pleroma.Web.Streamer.stream("public:local:media", activity) - end - end - end - else - if get_visibility(activity) == "direct", - do: Pleroma.Web.Streamer.stream("direct", activity) - end - end - end + def stream_out(_activity) do + :noop end def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex index dbd3542ea..3c26eb406 100644 --- a/lib/pleroma/web/mastodon_api/websocket_handler.ex +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.Streamer @behaviour :cowboy_websocket @@ -24,7 +25,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do ] @anonymous_streams ["public", "public:local", "hashtag"] - # Handled by periodic keepalive in Pleroma.Web.Streamer. + # Handled by periodic keepalive in Pleroma.Web.Streamer.Ping. @timeout :infinity def init(%{qs: qs} = req, state) do @@ -65,7 +66,7 @@ def websocket_info(:subscribe, state) do }, topic #{state.topic}" ) - Pleroma.Web.Streamer.add_socket(state.topic, streamer_socket(state)) + Streamer.add_socket(state.topic, streamer_socket(state)) {:ok, state} end @@ -80,7 +81,7 @@ def terminate(reason, _req, state) do }, topic #{state.topic || "?"}: #{inspect(reason)}" ) - Pleroma.Web.Streamer.remove_socket(state.topic, streamer_socket(state)) + Streamer.remove_socket(state.topic, streamer_socket(state)) :ok end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex deleted file mode 100644 index 587c43f40..000000000 --- a/lib/pleroma/web/streamer.ex +++ /dev/null @@ -1,318 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Streamer do - use GenServer - require Logger - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.Conversation.Participation - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Visibility - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.NotificationView - - @keepalive_interval :timer.seconds(30) - - def start_link(_) do - GenServer.start_link(__MODULE__, %{}, name: __MODULE__) - end - - def add_socket(topic, socket) do - GenServer.cast(__MODULE__, %{action: :add, socket: socket, topic: topic}) - end - - def remove_socket(topic, socket) do - GenServer.cast(__MODULE__, %{action: :remove, socket: socket, topic: topic}) - end - - def stream(topic, item) do - GenServer.cast(__MODULE__, %{action: :stream, topic: topic, item: item}) - end - - def init(args) do - Process.send_after(self(), %{action: :ping}, @keepalive_interval) - - {:ok, args} - end - - def handle_info(%{action: :ping}, topics) do - topics - |> Map.values() - |> List.flatten() - |> Enum.each(fn socket -> - Logger.debug("Sending keepalive ping") - send(socket.transport_pid, {:text, ""}) - end) - - Process.send_after(self(), %{action: :ping}, @keepalive_interval) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "direct", item: item}, topics) do - recipient_topics = - User.get_recipients_from_activity(item) - |> Enum.map(fn %{id: id} -> "direct:#{id}" end) - - Enum.each(recipient_topics || [], fn user_topic -> - Logger.debug("Trying to push direct message to #{user_topic}\n\n") - push_to_socket(topics, user_topic, item) - end) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "participation", item: participation}, topics) do - user_topic = "direct:#{participation.user_id}" - Logger.debug("Trying to push a conversation participation to #{user_topic}\n\n") - - push_to_socket(topics, user_topic, participation) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "list", item: item}, topics) do - # filter the recipient list if the activity is not public, see #270. - recipient_lists = - case Visibility.is_public?(item) do - true -> - Pleroma.List.get_lists_from_activity(item) - - _ -> - Pleroma.List.get_lists_from_activity(item) - |> Enum.filter(fn list -> - owner = User.get_cached_by_id(list.user_id) - - Visibility.visible_for_user?(item, owner) - end) - end - - recipient_topics = - recipient_lists - |> Enum.map(fn %{id: id} -> "list:#{id}" end) - - Enum.each(recipient_topics || [], fn list_topic -> - Logger.debug("Trying to push message to #{list_topic}\n\n") - push_to_socket(topics, list_topic, item) - end) - - {:noreply, topics} - end - - def handle_cast( - %{action: :stream, topic: topic, item: %Notification{} = item}, - topics - ) - when topic in ["user", "user:notification"] do - topics - |> Map.get("#{topic}:#{item.user_id}", []) - |> Enum.each(fn socket -> - with %User{} = user <- User.get_cached_by_ap_id(socket.assigns[:user].ap_id), - true <- should_send?(user, item) do - send( - socket.transport_pid, - {:text, represent_notification(socket.assigns[:user], item)} - ) - end - end) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "user", item: item}, topics) do - Logger.debug("Trying to push to users") - - recipient_topics = - User.get_recipients_from_activity(item) - |> Enum.map(fn %{id: id} -> "user:#{id}" end) - - Enum.each(recipient_topics, fn topic -> - push_to_socket(topics, topic, item) - end) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: topic, item: item}, topics) do - Logger.debug("Trying to push to #{topic}") - Logger.debug("Pushing item to #{topic}") - push_to_socket(topics, topic, item) - {:noreply, topics} - end - - def handle_cast(%{action: :add, topic: topic, socket: socket}, sockets) do - topic = internal_topic(topic, socket) - sockets_for_topic = sockets[topic] || [] - sockets_for_topic = Enum.uniq([socket | sockets_for_topic]) - sockets = Map.put(sockets, topic, sockets_for_topic) - Logger.debug("Got new conn for #{topic}") - {:noreply, sockets} - end - - def handle_cast(%{action: :remove, topic: topic, socket: socket}, sockets) do - topic = internal_topic(topic, socket) - sockets_for_topic = sockets[topic] || [] - sockets_for_topic = List.delete(sockets_for_topic, socket) - sockets = Map.put(sockets, topic, sockets_for_topic) - Logger.debug("Removed conn for #{topic}") - {:noreply, sockets} - end - - def handle_cast(m, state) do - Logger.info("Unknown: #{inspect(m)}, #{inspect(state)}") - {:noreply, state} - end - - defp represent_update(%Activity{} = activity, %User{} = user) do - %{ - event: "update", - payload: - Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", - activity: activity, - for: user - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - defp represent_update(%Activity{} = activity) do - %{ - event: "update", - payload: - Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", - activity: activity - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - def represent_conversation(%Participation{} = participation) do - %{ - event: "conversation", - payload: - Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ - participation: participation, - for: participation.user - }) - |> Jason.encode!() - } - |> Jason.encode!() - end - - @spec represent_notification(User.t(), Notification.t()) :: binary() - defp represent_notification(%User{} = user, %Notification{} = notify) do - %{ - event: "notification", - payload: - NotificationView.render( - "show.json", - %{notification: notify, for: user} - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - defp should_send?(%User{} = user, %Activity{} = item) do - blocks = user.info.blocks || [] - mutes = user.info.mutes || [] - reblog_mutes = user.info.muted_reblogs || [] - domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) - - with parent when not is_nil(parent) <- Object.normalize(item), - true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), - true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), - %{host: item_host} <- URI.parse(item.actor), - %{host: parent_host} <- URI.parse(parent.data["actor"]), - false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), - false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), - true <- thread_containment(item, user), - false <- CommonAPI.thread_muted?(user, item) do - true - else - _ -> false - end - end - - defp should_send?(%User{} = user, %Notification{activity: activity}) do - should_send?(user, activity) - end - - def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do - Enum.each(topics[topic] || [], fn socket -> - # Get the current user so we have up-to-date blocks etc. - if socket.assigns[:user] do - user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) - - if should_send?(user, item) do - send(socket.transport_pid, {:text, represent_update(item, user)}) - end - else - send(socket.transport_pid, {:text, represent_update(item)}) - end - end) - end - - def push_to_socket(topics, topic, %Participation{} = participation) do - Enum.each(topics[topic] || [], fn socket -> - send(socket.transport_pid, {:text, represent_conversation(participation)}) - end) - end - - def push_to_socket(topics, topic, %Activity{ - data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id} - }) do - Enum.each(topics[topic] || [], fn socket -> - send( - socket.transport_pid, - {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()} - ) - end) - end - - def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop - - def push_to_socket(topics, topic, item) do - Enum.each(topics[topic] || [], fn socket -> - # Get the current user so we have up-to-date blocks etc. - if socket.assigns[:user] do - user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) - blocks = user.info.blocks || [] - mutes = user.info.mutes || [] - - with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), - true <- thread_containment(item, user) do - send(socket.transport_pid, {:text, represent_update(item, user)}) - end - else - send(socket.transport_pid, {:text, represent_update(item)}) - end - end) - end - - defp internal_topic(topic, socket) when topic in ~w[user user:notification direct] do - "#{topic}:#{socket.assigns[:user].id}" - end - - defp internal_topic(topic, _), do: topic - - @spec thread_containment(Activity.t(), User.t()) :: boolean() - defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true - - defp thread_containment(activity, user) do - if Config.get([:instance, :skip_thread_containment]) do - true - else - ActivityPub.contain_activity(activity, user) - end - end -end diff --git a/lib/pleroma/web/streamer/ping.ex b/lib/pleroma/web/streamer/ping.ex new file mode 100644 index 000000000..f77cbb95c --- /dev/null +++ b/lib/pleroma/web/streamer/ping.ex @@ -0,0 +1,33 @@ +defmodule Pleroma.Web.Streamer.Ping do + use GenServer + require Logger + + alias Pleroma.Web.Streamer.State + alias Pleroma.Web.Streamer.StreamerSocket + + @keepalive_interval :timer.seconds(30) + + def start_link(opts) do + ping_interval = Keyword.get(opts, :ping_interval, @keepalive_interval) + GenServer.start_link(__MODULE__, %{ping_interval: ping_interval}, name: __MODULE__) + end + + def init(%{ping_interval: ping_interval} = args) do + Process.send_after(self(), :ping, ping_interval) + {:ok, args} + end + + def handle_info(:ping, %{ping_interval: ping_interval} = state) do + State.get_sockets() + |> Map.values() + |> List.flatten() + |> Enum.each(fn %StreamerSocket{transport_pid: transport_pid} -> + Logger.debug("Sending keepalive ping") + send(transport_pid, {:text, ""}) + end) + + Process.send_after(self(), :ping, ping_interval) + + {:noreply, state} + end +end diff --git a/lib/pleroma/web/streamer/state.ex b/lib/pleroma/web/streamer/state.ex new file mode 100644 index 000000000..7b5199068 --- /dev/null +++ b/lib/pleroma/web/streamer/state.ex @@ -0,0 +1,68 @@ +defmodule Pleroma.Web.Streamer.State do + use GenServer + require Logger + + alias Pleroma.Web.Streamer.StreamerSocket + + def start_link(_) do + GenServer.start_link(__MODULE__, %{sockets: %{}}, name: __MODULE__) + end + + def add_socket(topic, socket) do + GenServer.call(__MODULE__, {:add, socket, topic}) + end + + def remove_socket(topic, socket) do + GenServer.call(__MODULE__, {:remove, socket, topic}) + end + + def get_sockets do + %{sockets: stream_sockets} = GenServer.call(__MODULE__, :get_state) + stream_sockets + end + + def init(init_arg) do + {:ok, init_arg} + end + + def handle_call(:get_state, _from, state) do + {:reply, state, state} + end + + def handle_call({:add, socket, topic}, _from, %{sockets: sockets} = state) do + internal_topic = internal_topic(topic, socket) + stream_socket = StreamerSocket.from_socket(socket) + + sockets_for_topic = + sockets + |> Map.get(internal_topic, []) + |> List.insert_at(0, stream_socket) + |> Enum.uniq() + + state = put_in(state, [:sockets, internal_topic], sockets_for_topic) + Logger.debug("Got new conn for #{topic}") + {:reply, state, state} + end + + def handle_call({:remove, socket, topic}, _from, %{sockets: sockets} = state) do + internal_topic = internal_topic(topic, socket) + stream_socket = StreamerSocket.from_socket(socket) + + sockets_for_topic = + sockets + |> Map.get(internal_topic, []) + |> List.delete(stream_socket) + + state = Kernel.put_in(state, [:sockets, internal_topic], sockets_for_topic) + {:reply, state, state} + end + + defp internal_topic(topic, socket) + when topic in ~w[user user:notification direct] do + "#{topic}:#{socket.assigns[:user].id}" + end + + defp internal_topic(topic, _) do + topic + end +end diff --git a/lib/pleroma/web/streamer/streamer.ex b/lib/pleroma/web/streamer/streamer.ex new file mode 100644 index 000000000..8cf719277 --- /dev/null +++ b/lib/pleroma/web/streamer/streamer.ex @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Streamer do + alias Pleroma.Web.Streamer.State + alias Pleroma.Web.Streamer.Worker + + @timeout 60_000 + @mix_env Mix.env() + + def add_socket(topic, socket) do + State.add_socket(topic, socket) + end + + def remove_socket(topic, socket) do + State.remove_socket(topic, socket) + end + + def get_sockets do + State.get_sockets() + end + + def stream(topics, items) do + if should_send?() do + Task.async(fn -> + :poolboy.transaction( + :streamer_worker, + &Worker.stream(&1, topics, items), + @timeout + ) + end) + end + end + + def supervisor, do: Pleroma.Web.Streamer.Supervisor + + defp should_send? do + handle_should_send(@mix_env) + end + + defp handle_should_send(:test) do + case Process.whereis(:streamer_worker) do + nil -> + false + + pid -> + Process.alive?(pid) + end + end + + defp handle_should_send(_) do + true + end +end diff --git a/lib/pleroma/web/streamer/streamer_socket.ex b/lib/pleroma/web/streamer/streamer_socket.ex new file mode 100644 index 000000000..f006c0306 --- /dev/null +++ b/lib/pleroma/web/streamer/streamer_socket.ex @@ -0,0 +1,31 @@ +defmodule Pleroma.Web.Streamer.StreamerSocket do + defstruct transport_pid: nil, user: nil + + alias Pleroma.User + alias Pleroma.Web.Streamer.StreamerSocket + + def from_socket(%{ + transport_pid: transport_pid, + assigns: %{user: nil} + }) do + %StreamerSocket{ + transport_pid: transport_pid + } + end + + def from_socket(%{ + transport_pid: transport_pid, + assigns: %{user: %User{} = user} + }) do + %StreamerSocket{ + transport_pid: transport_pid, + user: user + } + end + + def from_socket(%{transport_pid: transport_pid}) do + %StreamerSocket{ + transport_pid: transport_pid + } + end +end diff --git a/lib/pleroma/web/streamer/supervisor.ex b/lib/pleroma/web/streamer/supervisor.ex new file mode 100644 index 000000000..6afe19323 --- /dev/null +++ b/lib/pleroma/web/streamer/supervisor.ex @@ -0,0 +1,33 @@ +defmodule Pleroma.Web.Streamer.Supervisor do + use Supervisor + + def start_link(opts) do + Supervisor.start_link(__MODULE__, opts, name: __MODULE__) + end + + def init(args) do + children = [ + {Pleroma.Web.Streamer.State, args}, + {Pleroma.Web.Streamer.Ping, args}, + :poolboy.child_spec(:streamer_worker, poolboy_config()) + ] + + opts = [strategy: :one_for_one, name: Pleroma.Web.Streamer.Supervisor] + Supervisor.init(children, opts) + end + + defp poolboy_config do + opts = + Pleroma.Config.get(:streamer, + workers: 3, + overflow_workers: 2 + ) + + [ + {:name, {:local, :streamer_worker}}, + {:worker_module, Pleroma.Web.Streamer.Worker}, + {:size, opts[:workers]}, + {:max_overflow, opts[:overflow_workers]} + ] + end +end diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex new file mode 100644 index 000000000..5804508eb --- /dev/null +++ b/lib/pleroma/web/streamer/worker.ex @@ -0,0 +1,220 @@ +defmodule Pleroma.Web.Streamer.Worker do + use GenServer + + require Logger + + alias Pleroma.Activity + alias Pleroma.Config + alias Pleroma.Conversation.Participation + alias Pleroma.Notification + alias Pleroma.Object + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Streamer.State + alias Pleroma.Web.Streamer.StreamerSocket + alias Pleroma.Web.StreamerView + + def start_link(_) do + GenServer.start_link(__MODULE__, %{}, []) + end + + def init(init_arg) do + {:ok, init_arg} + end + + def stream(pid, topics, items) do + GenServer.call(pid, {:stream, topics, items}) + end + + def handle_call({:stream, topics, item}, _from, state) when is_list(topics) do + Enum.each(topics, fn t -> + do_stream(%{topic: t, item: item}) + end) + + {:reply, state, state} + end + + def handle_call({:stream, topic, items}, _from, state) when is_list(items) do + Enum.each(items, fn i -> + do_stream(%{topic: topic, item: i}) + end) + + {:reply, state, state} + end + + def handle_call({:stream, topic, item}, _from, state) do + do_stream(%{topic: topic, item: item}) + + {:reply, state, state} + end + + defp do_stream(%{topic: "direct", item: item}) do + recipient_topics = + User.get_recipients_from_activity(item) + |> Enum.map(fn %{id: id} -> "direct:#{id}" end) + + Enum.each(recipient_topics, fn user_topic -> + Logger.debug("Trying to push direct message to #{user_topic}\n\n") + push_to_socket(State.get_sockets(), user_topic, item) + end) + end + + defp do_stream(%{topic: "participation", item: participation}) do + user_topic = "direct:#{participation.user_id}" + Logger.debug("Trying to push a conversation participation to #{user_topic}\n\n") + + push_to_socket(State.get_sockets(), user_topic, participation) + end + + defp do_stream(%{topic: "list", item: item}) do + # filter the recipient list if the activity is not public, see #270. + recipient_lists = + case Visibility.is_public?(item) do + true -> + Pleroma.List.get_lists_from_activity(item) + + _ -> + Pleroma.List.get_lists_from_activity(item) + |> Enum.filter(fn list -> + owner = User.get_cached_by_id(list.user_id) + + Visibility.visible_for_user?(item, owner) + end) + end + + recipient_topics = + recipient_lists + |> Enum.map(fn %{id: id} -> "list:#{id}" end) + + Enum.each(recipient_topics, fn list_topic -> + Logger.debug("Trying to push message to #{list_topic}\n\n") + push_to_socket(State.get_sockets(), list_topic, item) + end) + end + + defp do_stream(%{topic: topic, item: %Notification{} = item}) + when topic in ["user", "user:notification"] do + State.get_sockets() + |> Map.get("#{topic}:#{item.user_id}", []) + |> Enum.each(fn %StreamerSocket{transport_pid: transport_pid, user: socket_user} -> + with %User{} = user <- User.get_cached_by_ap_id(socket_user.ap_id), + true <- should_send?(user, item) do + send(transport_pid, {:text, StreamerView.render("notification.json", socket_user, item)}) + end + end) + end + + defp do_stream(%{topic: "user", item: item}) do + Logger.debug("Trying to push to users") + + recipient_topics = + User.get_recipients_from_activity(item) + |> Enum.map(fn %{id: id} -> "user:#{id}" end) + + Enum.each(recipient_topics, fn topic -> + push_to_socket(State.get_sockets(), topic, item) + end) + end + + defp do_stream(%{topic: topic, item: item}) do + Logger.debug("Trying to push to #{topic}") + Logger.debug("Pushing item to #{topic}") + push_to_socket(State.get_sockets(), topic, item) + end + + defp should_send?(%User{} = user, %Activity{} = item) do + blocks = user.info.blocks || [] + mutes = user.info.mutes || [] + reblog_mutes = user.info.muted_reblogs || [] + domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) + + with parent when not is_nil(parent) <- Object.normalize(item), + true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), + true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), + %{host: item_host} <- URI.parse(item.actor), + %{host: parent_host} <- URI.parse(parent.data["actor"]), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), + true <- thread_containment(item, user), + false <- CommonAPI.thread_muted?(user, item) do + true + else + _ -> false + end + end + + defp should_send?(%User{} = user, %Notification{activity: activity}) 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)}) + end) + end + + def push_to_socket(topics, topic, %Activity{ + data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id} + }) do + Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} -> + send( + transport_pid, + {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()} + ) + end) + end + + def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop + + def push_to_socket(topics, topic, 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) + blocks = user.info.blocks || [] + mutes = user.info.mutes || [] + + with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), + true <- thread_containment(item, user) 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 + + @spec thread_containment(Activity.t(), User.t()) :: boolean() + defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true + + defp thread_containment(activity, user) do + if Config.get([:instance, :skip_thread_containment]) do + true + else + ActivityPub.contain_activity(activity, user) + end + end +end diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex new file mode 100644 index 000000000..b13030fa0 --- /dev/null +++ b/lib/pleroma/web/views/streamer_view.ex @@ -0,0 +1,66 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StreamerView do + use Pleroma.Web, :view + + alias Pleroma.Activity + alias Pleroma.Conversation.Participation + alias Pleroma.Notification + alias Pleroma.User + alias Pleroma.Web.MastodonAPI.NotificationView + + def render("update.json", %Activity{} = activity, %User{} = user) do + %{ + event: "update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "status.json", + activity: activity, + for: user + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + def render("notification.json", %User{} = user, %Notification{} = notify) do + %{ + event: "notification", + payload: + NotificationView.render( + "show.json", + %{notification: notify, for: user} + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + def render("update.json", %Activity{} = activity) do + %{ + event: "update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "status.json", + activity: activity + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + def render("conversation.json", %Participation{} = participation) do + %{ + event: "conversation", + payload: + Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ + participation: participation, + for: participation.user + }) + |> Jason.encode!() + } + |> Jason.encode!() + end +end diff --git a/mix.exs b/mix.exs index f1e98585b..911ebad1d 100644 --- a/mix.exs +++ b/mix.exs @@ -144,6 +144,7 @@ defp deps do git: "https://git.pleroma.social/pleroma/http_signatures.git", ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"}, {:telemetry, "~> 0.3"}, + {:poolboy, "~> 1.5"}, {:prometheus_ex, "~> 3.0"}, {:prometheus_plugs, "~> 1.1"}, {:prometheus_phoenix, "~> 1.3"}, diff --git a/mix.lock b/mix.lock index 41697dd5c..0bf6a811e 100644 --- a/mix.lock +++ b/mix.lock @@ -73,6 +73,7 @@ "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, + "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, "postgrex": {:hex, :postgrex, "0.14.3", "5754dee2fdf6e9e508cbf49ab138df964278700b764177e8f3871e658b345a1e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.4.1", "1e96073b3ed7788053768fea779cbc896ddc3bdd9ba60687f2ad50b252ac87d6", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/test/activity/ir/topics_test.exs b/test/activity/ir/topics_test.exs new file mode 100644 index 000000000..e75f83586 --- /dev/null +++ b/test/activity/ir/topics_test.exs @@ -0,0 +1,141 @@ +defmodule Pleroma.Activity.Ir.TopicsTest do + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Activity.Ir.Topics + alias Pleroma.Object + + require Pleroma.Constants + + describe "poll answer" do + test "produce no topics" do + activity = %Activity{object: %Object{data: %{"type" => "Answer"}}} + + assert [] == Topics.get_activity_topics(activity) + end + end + + describe "non poll answer" do + test "always add user and list topics" do + activity = %Activity{object: %Object{data: %{"type" => "FooBar"}}} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "user") + assert Enum.member?(topics, "list") + end + end + + describe "public visibility" do + setup do + activity = %Activity{ + object: %Object{data: %{"type" => "Note"}}, + data: %{"to" => [Pleroma.Constants.as_public()]} + } + + {:ok, activity: activity} + end + + test "produces public topic", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public") + end + + test "local action produces public:local topic", %{activity: activity} do + activity = %{activity | local: true} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:local") + end + + test "non-local action does not produce public:local topic", %{activity: activity} do + activity = %{activity | local: false} + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "public:local") + end + end + + describe "public visibility create events" do + setup do + activity = %Activity{ + object: %Object{data: %{"type" => "Create", "attachment" => []}}, + data: %{"to" => [Pleroma.Constants.as_public()]} + } + + {:ok, activity: activity} + end + + test "with no attachments doesn't produce public:media topics", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "public:media") + refute Enum.member?(topics, "public:local:media") + end + + test "converts tags to hash tags", %{activity: %{object: %{data: data} = object} = activity} do + tagged_data = Map.put(data, "tag", ["foo", "bar"]) + activity = %{activity | object: %{object | data: tagged_data}} + + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "hashtag:foo") + assert Enum.member?(topics, "hashtag:bar") + end + + test "only converts strinngs to hash tags", %{ + activity: %{object: %{data: data} = object} = activity + } do + tagged_data = Map.put(data, "tag", [2]) + activity = %{activity | object: %{object | data: tagged_data}} + + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "hashtag:2") + end + end + + describe "public visibility create events with attachments" do + setup do + activity = %Activity{ + object: %Object{data: %{"type" => "Create", "attachment" => ["foo"]}}, + data: %{"to" => [Pleroma.Constants.as_public()]} + } + + {:ok, activity: activity} + end + + test "produce public:media topics", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:media") + end + + test "local produces public:local:media topics", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:local:media") + end + + test "non-local doesn't produce public:local:media topics", %{activity: activity} do + activity = %{activity | local: false} + + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "public:local:media") + end + end + + describe "non-public visibility" do + test "produces direct topic" do + activity = %Activity{object: %Object{data: %{"type" => "Note"}}, data: %{"to" => []}} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "direct") + refute Enum.member?(topics, "public") + refute Enum.member?(topics, "public:local") + refute Enum.member?(topics, "public:media") + refute Enum.member?(topics, "public:local:media") + end + end +end diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index 63bf73412..c04262808 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -11,7 +11,6 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do alias Pleroma.Integration.WebsocketClient alias Pleroma.Web.CommonAPI alias Pleroma.Web.OAuth - alias Pleroma.Web.Streamer @path Pleroma.Web.Endpoint.url() |> URI.parse() @@ -19,16 +18,6 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do |> Map.put(:path, "/api/v1/streaming") |> URI.to_string() - setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - end - def start_socket(qs \\ nil, headers \\ []) do path = case qs do @@ -53,12 +42,14 @@ test "requires authentication and a valid token for protected streams" do end) end + @tag needs_streamer: true test "allows public streams without authentication" do assert {:ok, _} = start_socket("?stream=public") assert {:ok, _} = start_socket("?stream=public:local") assert {:ok, _} = start_socket("?stream=hashtag&tag=lain") end + @tag needs_streamer: true test "receives well formatted events" do user = insert(:user) {:ok, _} = start_socket("?stream=public") @@ -103,6 +94,7 @@ test "accepts valid tokens", state do assert {:ok, _} = start_socket("?stream=user&access_token=#{state.token.token}") end + @tag needs_streamer: true test "accepts the 'user' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") @@ -111,6 +103,7 @@ test "accepts the 'user' stream", %{token: token} = _state do end) =~ ":badarg" end + @tag needs_streamer: true test "accepts the 'user:notification' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") @@ -119,6 +112,7 @@ test "accepts the 'user:notification' stream", %{token: token} = _state do end) =~ ":badarg" end + @tag needs_streamer: true test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}]) diff --git a/test/notification_test.exs b/test/notification_test.exs index 3be9db09b..3d2f9a8fc 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -69,16 +69,7 @@ test "does not create a notification for subscribed users if status is a reply" end describe "create_notification" do - setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - end - + @tag needs_streamer: true test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do user = insert(:user) task = Task.async(fn -> assert_receive {:text, _}, 4_000 end) diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index ec5892ff5..b39c70677 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -40,6 +40,10 @@ defmodule Pleroma.Web.ConnCase do Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) end + if tags[:needs_streamer] do + start_supervised(Pleroma.Web.Streamer.supervisor()) + end + {:ok, conn: Phoenix.ConnTest.build_conn()} end end diff --git a/test/support/data_case.ex b/test/support/data_case.ex index f3d98e7e3..17fa15214 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -39,6 +39,10 @@ defmodule Pleroma.DataCase do Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) end + if tags[:needs_streamer] do + start_supervised(Pleroma.Web.Streamer.supervisor()) + end + :ok end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index d0118fefa..4100108a5 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -38,9 +38,7 @@ test "it streams them out" do stream: fn _, _ -> nil end do ActivityPub.stream_out_participations(conversation.participations) - Enum.each(participations, fn participation -> - assert called(Pleroma.Web.Streamer.stream("participation", participation)) - end) + assert called(Pleroma.Web.Streamer.stream("participation", participations)) end end end diff --git a/test/web/streamer/ping_test.exs b/test/web/streamer/ping_test.exs new file mode 100644 index 000000000..3d52c00e4 --- /dev/null +++ b/test/web/streamer/ping_test.exs @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PingTest do + use Pleroma.DataCase + + import Pleroma.Factory + alias Pleroma.Web.Streamer + + setup do + start_supervised({Streamer.supervisor(), [ping_interval: 30]}) + + :ok + end + + describe "sockets" do + setup do + user = insert(:user) + {:ok, %{user: user}} + end + + test "it sends pings", %{user: user} do + task = + Task.async(fn -> + assert_receive {:text, received_event}, 40 + assert_receive {:text, received_event}, 40 + assert_receive {:text, received_event}, 40 + end) + + Streamer.add_socket("public", %{transport_pid: task.pid, assigns: %{user: user}}) + + Task.await(task) + end + end +end diff --git a/test/web/streamer/state_test.exs b/test/web/streamer/state_test.exs new file mode 100644 index 000000000..d1aeac541 --- /dev/null +++ b/test/web/streamer/state_test.exs @@ -0,0 +1,54 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StateTest do + use Pleroma.DataCase + + import Pleroma.Factory + alias Pleroma.Web.Streamer + alias Pleroma.Web.Streamer.StreamerSocket + + @moduletag needs_streamer: true + + describe "sockets" do + setup do + user = insert(:user) + user2 = insert(:user) + {:ok, %{user: user, user2: user2}} + end + + test "it can add a socket", %{user: user} do + Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) + + assert(%{"public" => [%StreamerSocket{transport_pid: 1}]} = Streamer.get_sockets()) + end + + test "it can add multiple sockets per user", %{user: user} do + Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) + Streamer.add_socket("public", %{transport_pid: 2, assigns: %{user: user}}) + + assert( + %{ + "public" => [ + %StreamerSocket{transport_pid: 2}, + %StreamerSocket{transport_pid: 1} + ] + } = Streamer.get_sockets() + ) + end + + test "it will not add a duplicate socket", %{user: user} do + Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) + Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) + + assert( + %{ + "activity" => [ + %StreamerSocket{transport_pid: 1} + ] + } = Streamer.get_sockets() + ) + end + end +end diff --git a/test/web/streamer_test.exs b/test/web/streamer/streamer_test.exs similarity index 86% rename from test/web/streamer_test.exs rename to test/web/streamer/streamer_test.exs index 96fa7645f..88847e20f 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -5,24 +5,20 @@ defmodule Pleroma.Web.StreamerTest do use Pleroma.DataCase + import Pleroma.Factory + alias Pleroma.List alias Pleroma.User alias Pleroma.Web.CommonAPI alias Pleroma.Web.Streamer - import Pleroma.Factory + alias Pleroma.Web.Streamer.StreamerSocket + alias Pleroma.Web.Streamer.Worker + @moduletag needs_streamer: true clear_config_all([:instance, :skip_thread_containment]) describe "user streams" do setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - user = insert(:user) notify = insert(:notification, user: user, activity: build(:note_activity)) {:ok, %{user: user, notify: notify}} @@ -125,11 +121,9 @@ test "it sends to public" do assert_receive {:text, _}, 4_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user - } + user: user } {:ok, activity} = CommonAPI.post(other_user, %{"status" => "Test"}) @@ -138,7 +132,7 @@ test "it sends to public" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) @@ -155,11 +149,9 @@ test "it sends to public" do assert received_event == expected_event end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user - } + user: user } {:ok, activity} = CommonAPI.delete(activity.id, other_user) @@ -168,7 +160,7 @@ test "it sends to public" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -189,9 +181,9 @@ test "it doesn't send to user if recipients invalid and thread containment is en ) task = Task.async(fn -> refute_receive {:text, _}, 1_000 end) - fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} topics = %{"public" => [fake_socket]} - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -211,9 +203,9 @@ test "it sends message if recipients invalid and thread containment is disabled" ) task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) - fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} topics = %{"public" => [fake_socket]} - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -233,9 +225,9 @@ test "it sends message if recipients invalid and thread containment is enabled b ) task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) - fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} topics = %{"public" => [fake_socket]} - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -251,11 +243,9 @@ test "it doesn't send to blocked users" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user - } + user: user } {:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"}) @@ -264,7 +254,7 @@ test "it doesn't send to blocked users" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -284,11 +274,9 @@ test "it doesn't send unwanted DMs to list" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user_a - } + user: user_a } {:ok, activity} = @@ -301,7 +289,7 @@ test "it doesn't send unwanted DMs to list" do "list:#{list.id}" => [fake_socket] } - Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) + Worker.handle_call({:stream, "list", activity}, self(), topics) Task.await(task) end @@ -318,11 +306,9 @@ test "it doesn't send unwanted private posts to list" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user_a - } + user: user_a } {:ok, activity} = @@ -335,12 +321,12 @@ test "it doesn't send unwanted private posts to list" do "list:#{list.id}" => [fake_socket] } - Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) + Worker.handle_call({:stream, "list", activity}, self(), topics) Task.await(task) end - test "it send wanted private posts to list" do + test "it sends wanted private posts to list" do user_a = insert(:user) user_b = insert(:user) @@ -354,11 +340,9 @@ test "it send wanted private posts to list" do assert_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user_a - } + user: user_a } {:ok, activity} = @@ -367,11 +351,12 @@ test "it send wanted private posts to list" do "visibility" => "private" }) - topics = %{ - "list:#{list.id}" => [fake_socket] - } + Streamer.add_socket( + "list:#{list.id}", + fake_socket + ) - Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) + Worker.handle_call({:stream, "list", activity}, self(), %{}) Task.await(task) end @@ -387,11 +372,9 @@ test "it doesn't send muted reblogs" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user1 - } + user: user1 } {:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"}) @@ -401,7 +384,7 @@ test "it doesn't send muted reblogs" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", announce_activity) + Worker.push_to_socket(topics, "public", announce_activity) Task.await(task) end @@ -417,6 +400,8 @@ test "it doesn't send posts from muted threads" do task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) + Process.sleep(4000) + Streamer.add_socket( "user", %{transport_pid: task.pid, assigns: %{user: user2}} @@ -428,14 +413,6 @@ test "it doesn't send posts from muted threads" do describe "direct streams" do setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - :ok end @@ -480,6 +457,8 @@ test "it doesn't send conversation update to the 'direct' streamj when the last refute_receive {:text, _}, 4_000 end) + Process.sleep(1000) + Streamer.add_socket( "direct", %{transport_pid: task.pid, assigns: %{user: user}} @@ -521,6 +500,8 @@ test "it sends conversation update to the 'direct' stream when a message is dele assert last_status["id"] == to_string(create_activity.id) end) + Process.sleep(1000) + Streamer.add_socket( "direct", %{transport_pid: task.pid, assigns: %{user: user}} From c623b4324deaf236334a0f77a81435b5bffadf3c Mon Sep 17 00:00:00 2001 From: kaniini Date: Mon, 16 Sep 2019 09:09:21 +0000 Subject: [PATCH 079/272] Revert "Merge branch 'streamer-refactoring' into 'develop'" This reverts merge request !1653 --- .gitignore | 4 - config/config.exs | 4 - lib/pleroma/activity/ir/topics.ex | 63 ---- lib/pleroma/application.ex | 2 +- lib/pleroma/notification.ex | 6 +- lib/pleroma/web/activity_pub/activity_pub.ex | 48 ++- .../web/mastodon_api/websocket_handler.ex | 7 +- lib/pleroma/web/streamer.ex | 318 ++++++++++++++++++ lib/pleroma/web/streamer/ping.ex | 33 -- lib/pleroma/web/streamer/state.ex | 68 ---- lib/pleroma/web/streamer/streamer.ex | 55 --- lib/pleroma/web/streamer/streamer_socket.ex | 31 -- lib/pleroma/web/streamer/supervisor.ex | 33 -- lib/pleroma/web/streamer/worker.ex | 220 ------------ lib/pleroma/web/views/streamer_view.ex | 66 ---- mix.exs | 1 - mix.lock | 1 - test/activity/ir/topics_test.exs | 141 -------- test/integration/mastodon_websocket_test.exs | 16 +- test/notification_test.exs | 11 +- test/support/conn_case.ex | 4 - test/support/data_case.ex | 4 - test/web/activity_pub/activity_pub_test.exs | 4 +- test/web/streamer/ping_test.exs | 36 -- test/web/streamer/state_test.exs | 54 --- test/web/{streamer => }/streamer_test.exs | 105 +++--- 26 files changed, 447 insertions(+), 888 deletions(-) delete mode 100644 lib/pleroma/activity/ir/topics.ex create mode 100644 lib/pleroma/web/streamer.ex delete mode 100644 lib/pleroma/web/streamer/ping.ex delete mode 100644 lib/pleroma/web/streamer/state.ex delete mode 100644 lib/pleroma/web/streamer/streamer.ex delete mode 100644 lib/pleroma/web/streamer/streamer_socket.ex delete mode 100644 lib/pleroma/web/streamer/supervisor.ex delete mode 100644 lib/pleroma/web/streamer/worker.ex delete mode 100644 lib/pleroma/web/views/streamer_view.ex delete mode 100644 test/activity/ir/topics_test.exs delete mode 100644 test/web/streamer/ping_test.exs delete mode 100644 test/web/streamer/state_test.exs rename test/web/{streamer => }/streamer_test.exs (86%) diff --git a/.gitignore b/.gitignore index 3b0c7d361..4e71a7df0 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,3 @@ docs/generated_config.md # Code test coverage /cover /Elixir.*.coverdata - -.idea -pleroma.iml - diff --git a/config/config.exs b/config/config.exs index b1b98af93..ab6e00c98 100644 --- a/config/config.exs +++ b/config/config.exs @@ -331,10 +331,6 @@ follow_handshake_timeout: 500, sign_object_fetches: true -config :pleroma, :streamer, - workers: 3, - overflow_workers: 2 - config :pleroma, :user, deny_follow_blocked: true config :pleroma, :mrf_normalize_markup, scrub_policy: Pleroma.HTML.Scrubber.Default diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex deleted file mode 100644 index 010897abc..000000000 --- a/lib/pleroma/activity/ir/topics.ex +++ /dev/null @@ -1,63 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Activity.Ir.Topics do - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Visibility - - def get_activity_topics(activity) do - activity - |> Object.normalize() - |> generate_topics(activity) - |> List.flatten() - end - - defp generate_topics(%{data: %{"type" => "Answer"}}, _) do - [] - end - - defp generate_topics(object, activity) do - ["user", "list"] ++ visibility_tags(object, activity) - end - - defp visibility_tags(object, activity) do - case Visibility.get_visibility(activity) do - "public" -> - if activity.local do - ["public", "public:local"] - else - ["public"] - end - |> item_creation_tags(object, activity) - - "direct" -> - ["direct"] - - _ -> - [] - end - end - - defp item_creation_tags(tags, %{data: %{"type" => "Create"}} = object, activity) do - tags ++ hashtags_to_topics(object) ++ attachment_topics(object, activity) - end - - defp item_creation_tags(tags, _, _) do - tags - end - - defp hashtags_to_topics(%{data: %{"tag" => tags}}) do - tags - |> Enum.filter(&is_bitstring(&1)) - |> Enum.map(fn tag -> "hashtag:" <> tag end) - end - - defp hashtags_to_topics(_), do: [] - - defp attachment_topics(%{data: %{"attachment" => []}}, _act), do: [] - - defp attachment_topics(_object, %{local: true}), do: ["public:media", "public:local:media"] - - defp attachment_topics(_object, _act), do: ["public:media"] -end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 3b37ce630..49094704b 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -141,7 +141,7 @@ defp oauth_cleanup_enabled?, defp streamer_child(:test), do: [] defp streamer_child(_) do - [Pleroma.Web.Streamer.supervisor()] + [Pleroma.Web.Streamer] end defp oauth_cleanup_child(true), diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 8012389ac..b7c880c51 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -210,10 +210,8 @@ def create_notification(%Activity{} = activity, %User{} = user) do unless skip?(activity, user) do notification = %Notification{user_id: user.id, activity: activity} {:ok, notification} = Repo.insert(notification) - - ["user", "user:notification"] - |> Streamer.stream(notification) - + Streamer.stream("user", notification) + Streamer.stream("user:notification", notification) Push.send(notification) notification end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index bc5ae7fbf..41f6a0f1f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -4,7 +4,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity - alias Pleroma.Activity.Ir.Topics alias Pleroma.Config alias Pleroma.Conversation alias Pleroma.Notification @@ -17,7 +16,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.Streamer alias Pleroma.Web.WebFinger alias Pleroma.Workers.BackgroundWorker @@ -189,7 +187,9 @@ def stream_out_participations(participations) do participations |> Repo.preload(:user) - Streamer.stream("participation", participations) + Enum.each(participations, fn participation -> + Pleroma.Web.Streamer.stream("participation", participation) + end) end def stream_out_participations(%Object{data: %{"context" => context}}, user) do @@ -208,15 +208,41 @@ def stream_out_participations(%Object{data: %{"context" => context}}, user) do def stream_out_participations(_, _), do: :noop - def stream_out(%Activity{data: %{"type" => data_type}} = activity) - when data_type in ["Create", "Announce", "Delete"] do - activity - |> Topics.get_activity_topics() - |> Streamer.stream(activity) - end + def stream_out(activity) do + if activity.data["type"] in ["Create", "Announce", "Delete"] do + object = Object.normalize(activity) + # Do not stream out poll replies + unless object.data["type"] == "Answer" do + Pleroma.Web.Streamer.stream("user", activity) + Pleroma.Web.Streamer.stream("list", activity) - def stream_out(_activity) do - :noop + if get_visibility(activity) == "public" do + Pleroma.Web.Streamer.stream("public", activity) + + if activity.local do + Pleroma.Web.Streamer.stream("public:local", activity) + end + + if activity.data["type"] in ["Create"] do + object.data + |> Map.get("tag", []) + |> Enum.filter(fn tag -> is_bitstring(tag) end) + |> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end) + + if object.data["attachment"] != [] do + Pleroma.Web.Streamer.stream("public:media", activity) + + if activity.local do + Pleroma.Web.Streamer.stream("public:local:media", activity) + end + end + end + else + if get_visibility(activity) == "direct", + do: Pleroma.Web.Streamer.stream("direct", activity) + end + end + end end def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex index 3c26eb406..dbd3542ea 100644 --- a/lib/pleroma/web/mastodon_api/websocket_handler.ex +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.OAuth.Token - alias Pleroma.Web.Streamer @behaviour :cowboy_websocket @@ -25,7 +24,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do ] @anonymous_streams ["public", "public:local", "hashtag"] - # Handled by periodic keepalive in Pleroma.Web.Streamer.Ping. + # Handled by periodic keepalive in Pleroma.Web.Streamer. @timeout :infinity def init(%{qs: qs} = req, state) do @@ -66,7 +65,7 @@ def websocket_info(:subscribe, state) do }, topic #{state.topic}" ) - Streamer.add_socket(state.topic, streamer_socket(state)) + Pleroma.Web.Streamer.add_socket(state.topic, streamer_socket(state)) {:ok, state} end @@ -81,7 +80,7 @@ def terminate(reason, _req, state) do }, topic #{state.topic || "?"}: #{inspect(reason)}" ) - Streamer.remove_socket(state.topic, streamer_socket(state)) + Pleroma.Web.Streamer.remove_socket(state.topic, streamer_socket(state)) :ok end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex new file mode 100644 index 000000000..587c43f40 --- /dev/null +++ b/lib/pleroma/web/streamer.ex @@ -0,0 +1,318 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Streamer do + use GenServer + require Logger + alias Pleroma.Activity + alias Pleroma.Config + alias Pleroma.Conversation.Participation + alias Pleroma.Notification + alias Pleroma.Object + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.NotificationView + + @keepalive_interval :timer.seconds(30) + + def start_link(_) do + GenServer.start_link(__MODULE__, %{}, name: __MODULE__) + end + + def add_socket(topic, socket) do + GenServer.cast(__MODULE__, %{action: :add, socket: socket, topic: topic}) + end + + def remove_socket(topic, socket) do + GenServer.cast(__MODULE__, %{action: :remove, socket: socket, topic: topic}) + end + + def stream(topic, item) do + GenServer.cast(__MODULE__, %{action: :stream, topic: topic, item: item}) + end + + def init(args) do + Process.send_after(self(), %{action: :ping}, @keepalive_interval) + + {:ok, args} + end + + def handle_info(%{action: :ping}, topics) do + topics + |> Map.values() + |> List.flatten() + |> Enum.each(fn socket -> + Logger.debug("Sending keepalive ping") + send(socket.transport_pid, {:text, ""}) + end) + + Process.send_after(self(), %{action: :ping}, @keepalive_interval) + + {:noreply, topics} + end + + def handle_cast(%{action: :stream, topic: "direct", item: item}, topics) do + recipient_topics = + User.get_recipients_from_activity(item) + |> Enum.map(fn %{id: id} -> "direct:#{id}" end) + + Enum.each(recipient_topics || [], fn user_topic -> + Logger.debug("Trying to push direct message to #{user_topic}\n\n") + push_to_socket(topics, user_topic, item) + end) + + {:noreply, topics} + end + + def handle_cast(%{action: :stream, topic: "participation", item: participation}, topics) do + user_topic = "direct:#{participation.user_id}" + Logger.debug("Trying to push a conversation participation to #{user_topic}\n\n") + + push_to_socket(topics, user_topic, participation) + + {:noreply, topics} + end + + def handle_cast(%{action: :stream, topic: "list", item: item}, topics) do + # filter the recipient list if the activity is not public, see #270. + recipient_lists = + case Visibility.is_public?(item) do + true -> + Pleroma.List.get_lists_from_activity(item) + + _ -> + Pleroma.List.get_lists_from_activity(item) + |> Enum.filter(fn list -> + owner = User.get_cached_by_id(list.user_id) + + Visibility.visible_for_user?(item, owner) + end) + end + + recipient_topics = + recipient_lists + |> Enum.map(fn %{id: id} -> "list:#{id}" end) + + Enum.each(recipient_topics || [], fn list_topic -> + Logger.debug("Trying to push message to #{list_topic}\n\n") + push_to_socket(topics, list_topic, item) + end) + + {:noreply, topics} + end + + def handle_cast( + %{action: :stream, topic: topic, item: %Notification{} = item}, + topics + ) + when topic in ["user", "user:notification"] do + topics + |> Map.get("#{topic}:#{item.user_id}", []) + |> Enum.each(fn socket -> + with %User{} = user <- User.get_cached_by_ap_id(socket.assigns[:user].ap_id), + true <- should_send?(user, item) do + send( + socket.transport_pid, + {:text, represent_notification(socket.assigns[:user], item)} + ) + end + end) + + {:noreply, topics} + end + + def handle_cast(%{action: :stream, topic: "user", item: item}, topics) do + Logger.debug("Trying to push to users") + + recipient_topics = + User.get_recipients_from_activity(item) + |> Enum.map(fn %{id: id} -> "user:#{id}" end) + + Enum.each(recipient_topics, fn topic -> + push_to_socket(topics, topic, item) + end) + + {:noreply, topics} + end + + def handle_cast(%{action: :stream, topic: topic, item: item}, topics) do + Logger.debug("Trying to push to #{topic}") + Logger.debug("Pushing item to #{topic}") + push_to_socket(topics, topic, item) + {:noreply, topics} + end + + def handle_cast(%{action: :add, topic: topic, socket: socket}, sockets) do + topic = internal_topic(topic, socket) + sockets_for_topic = sockets[topic] || [] + sockets_for_topic = Enum.uniq([socket | sockets_for_topic]) + sockets = Map.put(sockets, topic, sockets_for_topic) + Logger.debug("Got new conn for #{topic}") + {:noreply, sockets} + end + + def handle_cast(%{action: :remove, topic: topic, socket: socket}, sockets) do + topic = internal_topic(topic, socket) + sockets_for_topic = sockets[topic] || [] + sockets_for_topic = List.delete(sockets_for_topic, socket) + sockets = Map.put(sockets, topic, sockets_for_topic) + Logger.debug("Removed conn for #{topic}") + {:noreply, sockets} + end + + def handle_cast(m, state) do + Logger.info("Unknown: #{inspect(m)}, #{inspect(state)}") + {:noreply, state} + end + + defp represent_update(%Activity{} = activity, %User{} = user) do + %{ + event: "update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "status.json", + activity: activity, + for: user + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + defp represent_update(%Activity{} = activity) do + %{ + event: "update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "status.json", + activity: activity + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + def represent_conversation(%Participation{} = participation) do + %{ + event: "conversation", + payload: + Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ + participation: participation, + for: participation.user + }) + |> Jason.encode!() + } + |> Jason.encode!() + end + + @spec represent_notification(User.t(), Notification.t()) :: binary() + defp represent_notification(%User{} = user, %Notification{} = notify) do + %{ + event: "notification", + payload: + NotificationView.render( + "show.json", + %{notification: notify, for: user} + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + defp should_send?(%User{} = user, %Activity{} = item) do + blocks = user.info.blocks || [] + mutes = user.info.mutes || [] + reblog_mutes = user.info.muted_reblogs || [] + domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) + + with parent when not is_nil(parent) <- Object.normalize(item), + true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), + true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), + %{host: item_host} <- URI.parse(item.actor), + %{host: parent_host} <- URI.parse(parent.data["actor"]), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), + true <- thread_containment(item, user), + false <- CommonAPI.thread_muted?(user, item) do + true + else + _ -> false + end + end + + defp should_send?(%User{} = user, %Notification{activity: activity}) do + should_send?(user, activity) + end + + def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do + Enum.each(topics[topic] || [], fn socket -> + # Get the current user so we have up-to-date blocks etc. + if socket.assigns[:user] do + user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) + + if should_send?(user, item) do + send(socket.transport_pid, {:text, represent_update(item, user)}) + end + else + send(socket.transport_pid, {:text, represent_update(item)}) + end + end) + end + + def push_to_socket(topics, topic, %Participation{} = participation) do + Enum.each(topics[topic] || [], fn socket -> + send(socket.transport_pid, {:text, represent_conversation(participation)}) + end) + end + + def push_to_socket(topics, topic, %Activity{ + data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id} + }) do + Enum.each(topics[topic] || [], fn socket -> + send( + socket.transport_pid, + {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()} + ) + end) + end + + def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop + + def push_to_socket(topics, topic, item) do + Enum.each(topics[topic] || [], fn socket -> + # Get the current user so we have up-to-date blocks etc. + if socket.assigns[:user] do + user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) + blocks = user.info.blocks || [] + mutes = user.info.mutes || [] + + with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), + true <- thread_containment(item, user) do + send(socket.transport_pid, {:text, represent_update(item, user)}) + end + else + send(socket.transport_pid, {:text, represent_update(item)}) + end + end) + end + + defp internal_topic(topic, socket) when topic in ~w[user user:notification direct] do + "#{topic}:#{socket.assigns[:user].id}" + end + + defp internal_topic(topic, _), do: topic + + @spec thread_containment(Activity.t(), User.t()) :: boolean() + defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true + + defp thread_containment(activity, user) do + if Config.get([:instance, :skip_thread_containment]) do + true + else + ActivityPub.contain_activity(activity, user) + end + end +end diff --git a/lib/pleroma/web/streamer/ping.ex b/lib/pleroma/web/streamer/ping.ex deleted file mode 100644 index f77cbb95c..000000000 --- a/lib/pleroma/web/streamer/ping.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule Pleroma.Web.Streamer.Ping do - use GenServer - require Logger - - alias Pleroma.Web.Streamer.State - alias Pleroma.Web.Streamer.StreamerSocket - - @keepalive_interval :timer.seconds(30) - - def start_link(opts) do - ping_interval = Keyword.get(opts, :ping_interval, @keepalive_interval) - GenServer.start_link(__MODULE__, %{ping_interval: ping_interval}, name: __MODULE__) - end - - def init(%{ping_interval: ping_interval} = args) do - Process.send_after(self(), :ping, ping_interval) - {:ok, args} - end - - def handle_info(:ping, %{ping_interval: ping_interval} = state) do - State.get_sockets() - |> Map.values() - |> List.flatten() - |> Enum.each(fn %StreamerSocket{transport_pid: transport_pid} -> - Logger.debug("Sending keepalive ping") - send(transport_pid, {:text, ""}) - end) - - Process.send_after(self(), :ping, ping_interval) - - {:noreply, state} - end -end diff --git a/lib/pleroma/web/streamer/state.ex b/lib/pleroma/web/streamer/state.ex deleted file mode 100644 index 7b5199068..000000000 --- a/lib/pleroma/web/streamer/state.ex +++ /dev/null @@ -1,68 +0,0 @@ -defmodule Pleroma.Web.Streamer.State do - use GenServer - require Logger - - alias Pleroma.Web.Streamer.StreamerSocket - - def start_link(_) do - GenServer.start_link(__MODULE__, %{sockets: %{}}, name: __MODULE__) - end - - def add_socket(topic, socket) do - GenServer.call(__MODULE__, {:add, socket, topic}) - end - - def remove_socket(topic, socket) do - GenServer.call(__MODULE__, {:remove, socket, topic}) - end - - def get_sockets do - %{sockets: stream_sockets} = GenServer.call(__MODULE__, :get_state) - stream_sockets - end - - def init(init_arg) do - {:ok, init_arg} - end - - def handle_call(:get_state, _from, state) do - {:reply, state, state} - end - - def handle_call({:add, socket, topic}, _from, %{sockets: sockets} = state) do - internal_topic = internal_topic(topic, socket) - stream_socket = StreamerSocket.from_socket(socket) - - sockets_for_topic = - sockets - |> Map.get(internal_topic, []) - |> List.insert_at(0, stream_socket) - |> Enum.uniq() - - state = put_in(state, [:sockets, internal_topic], sockets_for_topic) - Logger.debug("Got new conn for #{topic}") - {:reply, state, state} - end - - def handle_call({:remove, socket, topic}, _from, %{sockets: sockets} = state) do - internal_topic = internal_topic(topic, socket) - stream_socket = StreamerSocket.from_socket(socket) - - sockets_for_topic = - sockets - |> Map.get(internal_topic, []) - |> List.delete(stream_socket) - - state = Kernel.put_in(state, [:sockets, internal_topic], sockets_for_topic) - {:reply, state, state} - end - - defp internal_topic(topic, socket) - when topic in ~w[user user:notification direct] do - "#{topic}:#{socket.assigns[:user].id}" - end - - defp internal_topic(topic, _) do - topic - end -end diff --git a/lib/pleroma/web/streamer/streamer.ex b/lib/pleroma/web/streamer/streamer.ex deleted file mode 100644 index 8cf719277..000000000 --- a/lib/pleroma/web/streamer/streamer.ex +++ /dev/null @@ -1,55 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Streamer do - alias Pleroma.Web.Streamer.State - alias Pleroma.Web.Streamer.Worker - - @timeout 60_000 - @mix_env Mix.env() - - def add_socket(topic, socket) do - State.add_socket(topic, socket) - end - - def remove_socket(topic, socket) do - State.remove_socket(topic, socket) - end - - def get_sockets do - State.get_sockets() - end - - def stream(topics, items) do - if should_send?() do - Task.async(fn -> - :poolboy.transaction( - :streamer_worker, - &Worker.stream(&1, topics, items), - @timeout - ) - end) - end - end - - def supervisor, do: Pleroma.Web.Streamer.Supervisor - - defp should_send? do - handle_should_send(@mix_env) - end - - defp handle_should_send(:test) do - case Process.whereis(:streamer_worker) do - nil -> - false - - pid -> - Process.alive?(pid) - end - end - - defp handle_should_send(_) do - true - end -end diff --git a/lib/pleroma/web/streamer/streamer_socket.ex b/lib/pleroma/web/streamer/streamer_socket.ex deleted file mode 100644 index f006c0306..000000000 --- a/lib/pleroma/web/streamer/streamer_socket.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule Pleroma.Web.Streamer.StreamerSocket do - defstruct transport_pid: nil, user: nil - - alias Pleroma.User - alias Pleroma.Web.Streamer.StreamerSocket - - def from_socket(%{ - transport_pid: transport_pid, - assigns: %{user: nil} - }) do - %StreamerSocket{ - transport_pid: transport_pid - } - end - - def from_socket(%{ - transport_pid: transport_pid, - assigns: %{user: %User{} = user} - }) do - %StreamerSocket{ - transport_pid: transport_pid, - user: user - } - end - - def from_socket(%{transport_pid: transport_pid}) do - %StreamerSocket{ - transport_pid: transport_pid - } - end -end diff --git a/lib/pleroma/web/streamer/supervisor.ex b/lib/pleroma/web/streamer/supervisor.ex deleted file mode 100644 index 6afe19323..000000000 --- a/lib/pleroma/web/streamer/supervisor.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule Pleroma.Web.Streamer.Supervisor do - use Supervisor - - def start_link(opts) do - Supervisor.start_link(__MODULE__, opts, name: __MODULE__) - end - - def init(args) do - children = [ - {Pleroma.Web.Streamer.State, args}, - {Pleroma.Web.Streamer.Ping, args}, - :poolboy.child_spec(:streamer_worker, poolboy_config()) - ] - - opts = [strategy: :one_for_one, name: Pleroma.Web.Streamer.Supervisor] - Supervisor.init(children, opts) - end - - defp poolboy_config do - opts = - Pleroma.Config.get(:streamer, - workers: 3, - overflow_workers: 2 - ) - - [ - {:name, {:local, :streamer_worker}}, - {:worker_module, Pleroma.Web.Streamer.Worker}, - {:size, opts[:workers]}, - {:max_overflow, opts[:overflow_workers]} - ] - end -end diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex deleted file mode 100644 index 5804508eb..000000000 --- a/lib/pleroma/web/streamer/worker.ex +++ /dev/null @@ -1,220 +0,0 @@ -defmodule Pleroma.Web.Streamer.Worker do - use GenServer - - require Logger - - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.Conversation.Participation - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Visibility - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Streamer.State - alias Pleroma.Web.Streamer.StreamerSocket - alias Pleroma.Web.StreamerView - - def start_link(_) do - GenServer.start_link(__MODULE__, %{}, []) - end - - def init(init_arg) do - {:ok, init_arg} - end - - def stream(pid, topics, items) do - GenServer.call(pid, {:stream, topics, items}) - end - - def handle_call({:stream, topics, item}, _from, state) when is_list(topics) do - Enum.each(topics, fn t -> - do_stream(%{topic: t, item: item}) - end) - - {:reply, state, state} - end - - def handle_call({:stream, topic, items}, _from, state) when is_list(items) do - Enum.each(items, fn i -> - do_stream(%{topic: topic, item: i}) - end) - - {:reply, state, state} - end - - def handle_call({:stream, topic, item}, _from, state) do - do_stream(%{topic: topic, item: item}) - - {:reply, state, state} - end - - defp do_stream(%{topic: "direct", item: item}) do - recipient_topics = - User.get_recipients_from_activity(item) - |> Enum.map(fn %{id: id} -> "direct:#{id}" end) - - Enum.each(recipient_topics, fn user_topic -> - Logger.debug("Trying to push direct message to #{user_topic}\n\n") - push_to_socket(State.get_sockets(), user_topic, item) - end) - end - - defp do_stream(%{topic: "participation", item: participation}) do - user_topic = "direct:#{participation.user_id}" - Logger.debug("Trying to push a conversation participation to #{user_topic}\n\n") - - push_to_socket(State.get_sockets(), user_topic, participation) - end - - defp do_stream(%{topic: "list", item: item}) do - # filter the recipient list if the activity is not public, see #270. - recipient_lists = - case Visibility.is_public?(item) do - true -> - Pleroma.List.get_lists_from_activity(item) - - _ -> - Pleroma.List.get_lists_from_activity(item) - |> Enum.filter(fn list -> - owner = User.get_cached_by_id(list.user_id) - - Visibility.visible_for_user?(item, owner) - end) - end - - recipient_topics = - recipient_lists - |> Enum.map(fn %{id: id} -> "list:#{id}" end) - - Enum.each(recipient_topics, fn list_topic -> - Logger.debug("Trying to push message to #{list_topic}\n\n") - push_to_socket(State.get_sockets(), list_topic, item) - end) - end - - defp do_stream(%{topic: topic, item: %Notification{} = item}) - when topic in ["user", "user:notification"] do - State.get_sockets() - |> Map.get("#{topic}:#{item.user_id}", []) - |> Enum.each(fn %StreamerSocket{transport_pid: transport_pid, user: socket_user} -> - with %User{} = user <- User.get_cached_by_ap_id(socket_user.ap_id), - true <- should_send?(user, item) do - send(transport_pid, {:text, StreamerView.render("notification.json", socket_user, item)}) - end - end) - end - - defp do_stream(%{topic: "user", item: item}) do - Logger.debug("Trying to push to users") - - recipient_topics = - User.get_recipients_from_activity(item) - |> Enum.map(fn %{id: id} -> "user:#{id}" end) - - Enum.each(recipient_topics, fn topic -> - push_to_socket(State.get_sockets(), topic, item) - end) - end - - defp do_stream(%{topic: topic, item: item}) do - Logger.debug("Trying to push to #{topic}") - Logger.debug("Pushing item to #{topic}") - push_to_socket(State.get_sockets(), topic, item) - end - - defp should_send?(%User{} = user, %Activity{} = item) do - blocks = user.info.blocks || [] - mutes = user.info.mutes || [] - reblog_mutes = user.info.muted_reblogs || [] - domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) - - with parent when not is_nil(parent) <- Object.normalize(item), - true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), - true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), - %{host: item_host} <- URI.parse(item.actor), - %{host: parent_host} <- URI.parse(parent.data["actor"]), - false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), - false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), - true <- thread_containment(item, user), - false <- CommonAPI.thread_muted?(user, item) do - true - else - _ -> false - end - end - - defp should_send?(%User{} = user, %Notification{activity: activity}) 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)}) - end) - end - - def push_to_socket(topics, topic, %Activity{ - data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id} - }) do - Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} -> - send( - transport_pid, - {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()} - ) - end) - end - - def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop - - def push_to_socket(topics, topic, 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) - blocks = user.info.blocks || [] - mutes = user.info.mutes || [] - - with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), - true <- thread_containment(item, user) 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 - - @spec thread_containment(Activity.t(), User.t()) :: boolean() - defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true - - defp thread_containment(activity, user) do - if Config.get([:instance, :skip_thread_containment]) do - true - else - ActivityPub.contain_activity(activity, user) - end - end -end diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex deleted file mode 100644 index b13030fa0..000000000 --- a/lib/pleroma/web/views/streamer_view.ex +++ /dev/null @@ -1,66 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.StreamerView do - use Pleroma.Web, :view - - alias Pleroma.Activity - alias Pleroma.Conversation.Participation - alias Pleroma.Notification - alias Pleroma.User - alias Pleroma.Web.MastodonAPI.NotificationView - - def render("update.json", %Activity{} = activity, %User{} = user) do - %{ - event: "update", - payload: - Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", - activity: activity, - for: user - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - def render("notification.json", %User{} = user, %Notification{} = notify) do - %{ - event: "notification", - payload: - NotificationView.render( - "show.json", - %{notification: notify, for: user} - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - def render("update.json", %Activity{} = activity) do - %{ - event: "update", - payload: - Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", - activity: activity - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - def render("conversation.json", %Participation{} = participation) do - %{ - event: "conversation", - payload: - Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ - participation: participation, - for: participation.user - }) - |> Jason.encode!() - } - |> Jason.encode!() - end -end diff --git a/mix.exs b/mix.exs index 911ebad1d..f1e98585b 100644 --- a/mix.exs +++ b/mix.exs @@ -144,7 +144,6 @@ defp deps do git: "https://git.pleroma.social/pleroma/http_signatures.git", ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"}, {:telemetry, "~> 0.3"}, - {:poolboy, "~> 1.5"}, {:prometheus_ex, "~> 3.0"}, {:prometheus_plugs, "~> 1.1"}, {:prometheus_phoenix, "~> 1.3"}, diff --git a/mix.lock b/mix.lock index 0bf6a811e..41697dd5c 100644 --- a/mix.lock +++ b/mix.lock @@ -73,7 +73,6 @@ "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, - "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, "postgrex": {:hex, :postgrex, "0.14.3", "5754dee2fdf6e9e508cbf49ab138df964278700b764177e8f3871e658b345a1e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.4.1", "1e96073b3ed7788053768fea779cbc896ddc3bdd9ba60687f2ad50b252ac87d6", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/test/activity/ir/topics_test.exs b/test/activity/ir/topics_test.exs deleted file mode 100644 index e75f83586..000000000 --- a/test/activity/ir/topics_test.exs +++ /dev/null @@ -1,141 +0,0 @@ -defmodule Pleroma.Activity.Ir.TopicsTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Activity.Ir.Topics - alias Pleroma.Object - - require Pleroma.Constants - - describe "poll answer" do - test "produce no topics" do - activity = %Activity{object: %Object{data: %{"type" => "Answer"}}} - - assert [] == Topics.get_activity_topics(activity) - end - end - - describe "non poll answer" do - test "always add user and list topics" do - activity = %Activity{object: %Object{data: %{"type" => "FooBar"}}} - topics = Topics.get_activity_topics(activity) - - assert Enum.member?(topics, "user") - assert Enum.member?(topics, "list") - end - end - - describe "public visibility" do - setup do - activity = %Activity{ - object: %Object{data: %{"type" => "Note"}}, - data: %{"to" => [Pleroma.Constants.as_public()]} - } - - {:ok, activity: activity} - end - - test "produces public topic", %{activity: activity} do - topics = Topics.get_activity_topics(activity) - - assert Enum.member?(topics, "public") - end - - test "local action produces public:local topic", %{activity: activity} do - activity = %{activity | local: true} - topics = Topics.get_activity_topics(activity) - - assert Enum.member?(topics, "public:local") - end - - test "non-local action does not produce public:local topic", %{activity: activity} do - activity = %{activity | local: false} - topics = Topics.get_activity_topics(activity) - - refute Enum.member?(topics, "public:local") - end - end - - describe "public visibility create events" do - setup do - activity = %Activity{ - object: %Object{data: %{"type" => "Create", "attachment" => []}}, - data: %{"to" => [Pleroma.Constants.as_public()]} - } - - {:ok, activity: activity} - end - - test "with no attachments doesn't produce public:media topics", %{activity: activity} do - topics = Topics.get_activity_topics(activity) - - refute Enum.member?(topics, "public:media") - refute Enum.member?(topics, "public:local:media") - end - - test "converts tags to hash tags", %{activity: %{object: %{data: data} = object} = activity} do - tagged_data = Map.put(data, "tag", ["foo", "bar"]) - activity = %{activity | object: %{object | data: tagged_data}} - - topics = Topics.get_activity_topics(activity) - - assert Enum.member?(topics, "hashtag:foo") - assert Enum.member?(topics, "hashtag:bar") - end - - test "only converts strinngs to hash tags", %{ - activity: %{object: %{data: data} = object} = activity - } do - tagged_data = Map.put(data, "tag", [2]) - activity = %{activity | object: %{object | data: tagged_data}} - - topics = Topics.get_activity_topics(activity) - - refute Enum.member?(topics, "hashtag:2") - end - end - - describe "public visibility create events with attachments" do - setup do - activity = %Activity{ - object: %Object{data: %{"type" => "Create", "attachment" => ["foo"]}}, - data: %{"to" => [Pleroma.Constants.as_public()]} - } - - {:ok, activity: activity} - end - - test "produce public:media topics", %{activity: activity} do - topics = Topics.get_activity_topics(activity) - - assert Enum.member?(topics, "public:media") - end - - test "local produces public:local:media topics", %{activity: activity} do - topics = Topics.get_activity_topics(activity) - - assert Enum.member?(topics, "public:local:media") - end - - test "non-local doesn't produce public:local:media topics", %{activity: activity} do - activity = %{activity | local: false} - - topics = Topics.get_activity_topics(activity) - - refute Enum.member?(topics, "public:local:media") - end - end - - describe "non-public visibility" do - test "produces direct topic" do - activity = %Activity{object: %Object{data: %{"type" => "Note"}}, data: %{"to" => []}} - topics = Topics.get_activity_topics(activity) - - assert Enum.member?(topics, "direct") - refute Enum.member?(topics, "public") - refute Enum.member?(topics, "public:local") - refute Enum.member?(topics, "public:media") - refute Enum.member?(topics, "public:local:media") - end - end -end diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index c04262808..63bf73412 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -11,6 +11,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do alias Pleroma.Integration.WebsocketClient alias Pleroma.Web.CommonAPI alias Pleroma.Web.OAuth + alias Pleroma.Web.Streamer @path Pleroma.Web.Endpoint.url() |> URI.parse() @@ -18,6 +19,16 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do |> Map.put(:path, "/api/v1/streaming") |> URI.to_string() + setup do + GenServer.start(Streamer, %{}, name: Streamer) + + on_exit(fn -> + if pid = Process.whereis(Streamer) do + Process.exit(pid, :kill) + end + end) + end + def start_socket(qs \\ nil, headers \\ []) do path = case qs do @@ -42,14 +53,12 @@ test "requires authentication and a valid token for protected streams" do end) end - @tag needs_streamer: true test "allows public streams without authentication" do assert {:ok, _} = start_socket("?stream=public") assert {:ok, _} = start_socket("?stream=public:local") assert {:ok, _} = start_socket("?stream=hashtag&tag=lain") end - @tag needs_streamer: true test "receives well formatted events" do user = insert(:user) {:ok, _} = start_socket("?stream=public") @@ -94,7 +103,6 @@ test "accepts valid tokens", state do assert {:ok, _} = start_socket("?stream=user&access_token=#{state.token.token}") end - @tag needs_streamer: true test "accepts the 'user' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") @@ -103,7 +111,6 @@ test "accepts the 'user' stream", %{token: token} = _state do end) =~ ":badarg" end - @tag needs_streamer: true test "accepts the 'user:notification' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") @@ -112,7 +119,6 @@ test "accepts the 'user:notification' stream", %{token: token} = _state do end) =~ ":badarg" end - @tag needs_streamer: true test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}]) diff --git a/test/notification_test.exs b/test/notification_test.exs index 3d2f9a8fc..3be9db09b 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -69,7 +69,16 @@ test "does not create a notification for subscribed users if status is a reply" end describe "create_notification" do - @tag needs_streamer: true + setup do + GenServer.start(Streamer, %{}, name: Streamer) + + on_exit(fn -> + if pid = Process.whereis(Streamer) do + Process.exit(pid, :kill) + end + end) + end + test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do user = insert(:user) task = Task.async(fn -> assert_receive {:text, _}, 4_000 end) diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index b39c70677..ec5892ff5 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -40,10 +40,6 @@ defmodule Pleroma.Web.ConnCase do Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) end - if tags[:needs_streamer] do - start_supervised(Pleroma.Web.Streamer.supervisor()) - end - {:ok, conn: Phoenix.ConnTest.build_conn()} end end diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 17fa15214..f3d98e7e3 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -39,10 +39,6 @@ defmodule Pleroma.DataCase do Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) end - if tags[:needs_streamer] do - start_supervised(Pleroma.Web.Streamer.supervisor()) - end - :ok end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 4100108a5..d0118fefa 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -38,7 +38,9 @@ test "it streams them out" do stream: fn _, _ -> nil end do ActivityPub.stream_out_participations(conversation.participations) - assert called(Pleroma.Web.Streamer.stream("participation", participations)) + Enum.each(participations, fn participation -> + assert called(Pleroma.Web.Streamer.stream("participation", participation)) + end) end end end diff --git a/test/web/streamer/ping_test.exs b/test/web/streamer/ping_test.exs deleted file mode 100644 index 3d52c00e4..000000000 --- a/test/web/streamer/ping_test.exs +++ /dev/null @@ -1,36 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PingTest do - use Pleroma.DataCase - - import Pleroma.Factory - alias Pleroma.Web.Streamer - - setup do - start_supervised({Streamer.supervisor(), [ping_interval: 30]}) - - :ok - end - - describe "sockets" do - setup do - user = insert(:user) - {:ok, %{user: user}} - end - - test "it sends pings", %{user: user} do - task = - Task.async(fn -> - assert_receive {:text, received_event}, 40 - assert_receive {:text, received_event}, 40 - assert_receive {:text, received_event}, 40 - end) - - Streamer.add_socket("public", %{transport_pid: task.pid, assigns: %{user: user}}) - - Task.await(task) - end - end -end diff --git a/test/web/streamer/state_test.exs b/test/web/streamer/state_test.exs deleted file mode 100644 index d1aeac541..000000000 --- a/test/web/streamer/state_test.exs +++ /dev/null @@ -1,54 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.StateTest do - use Pleroma.DataCase - - import Pleroma.Factory - alias Pleroma.Web.Streamer - alias Pleroma.Web.Streamer.StreamerSocket - - @moduletag needs_streamer: true - - describe "sockets" do - setup do - user = insert(:user) - user2 = insert(:user) - {:ok, %{user: user, user2: user2}} - end - - test "it can add a socket", %{user: user} do - Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) - - assert(%{"public" => [%StreamerSocket{transport_pid: 1}]} = Streamer.get_sockets()) - end - - test "it can add multiple sockets per user", %{user: user} do - Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) - Streamer.add_socket("public", %{transport_pid: 2, assigns: %{user: user}}) - - assert( - %{ - "public" => [ - %StreamerSocket{transport_pid: 2}, - %StreamerSocket{transport_pid: 1} - ] - } = Streamer.get_sockets() - ) - end - - test "it will not add a duplicate socket", %{user: user} do - Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) - Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) - - assert( - %{ - "activity" => [ - %StreamerSocket{transport_pid: 1} - ] - } = Streamer.get_sockets() - ) - end - end -end diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer_test.exs similarity index 86% rename from test/web/streamer/streamer_test.exs rename to test/web/streamer_test.exs index 88847e20f..96fa7645f 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -5,20 +5,24 @@ defmodule Pleroma.Web.StreamerTest do use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.List alias Pleroma.User alias Pleroma.Web.CommonAPI alias Pleroma.Web.Streamer - alias Pleroma.Web.Streamer.StreamerSocket - alias Pleroma.Web.Streamer.Worker + import Pleroma.Factory - @moduletag needs_streamer: true clear_config_all([:instance, :skip_thread_containment]) describe "user streams" do setup do + GenServer.start(Streamer, %{}, name: Streamer) + + on_exit(fn -> + if pid = Process.whereis(Streamer) do + Process.exit(pid, :kill) + end + end) + user = insert(:user) notify = insert(:notification, user: user, activity: build(:note_activity)) {:ok, %{user: user, notify: notify}} @@ -121,9 +125,11 @@ test "it sends to public" do assert_receive {:text, _}, 4_000 end) - fake_socket = %StreamerSocket{ + fake_socket = %{ transport_pid: task.pid, - user: user + assigns: %{ + user: user + } } {:ok, activity} = CommonAPI.post(other_user, %{"status" => "Test"}) @@ -132,7 +138,7 @@ test "it sends to public" do "public" => [fake_socket] } - Worker.push_to_socket(topics, "public", activity) + Streamer.push_to_socket(topics, "public", activity) Task.await(task) @@ -149,9 +155,11 @@ test "it sends to public" do assert received_event == expected_event end) - fake_socket = %StreamerSocket{ + fake_socket = %{ transport_pid: task.pid, - user: user + assigns: %{ + user: user + } } {:ok, activity} = CommonAPI.delete(activity.id, other_user) @@ -160,7 +168,7 @@ test "it sends to public" do "public" => [fake_socket] } - Worker.push_to_socket(topics, "public", activity) + Streamer.push_to_socket(topics, "public", activity) Task.await(task) end @@ -181,9 +189,9 @@ test "it doesn't send to user if recipients invalid and thread containment is en ) task = Task.async(fn -> refute_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} topics = %{"public" => [fake_socket]} - Worker.push_to_socket(topics, "public", activity) + Streamer.push_to_socket(topics, "public", activity) Task.await(task) end @@ -203,9 +211,9 @@ test "it sends message if recipients invalid and thread containment is disabled" ) task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} topics = %{"public" => [fake_socket]} - Worker.push_to_socket(topics, "public", activity) + Streamer.push_to_socket(topics, "public", activity) Task.await(task) end @@ -225,9 +233,9 @@ test "it sends message if recipients invalid and thread containment is enabled b ) task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} topics = %{"public" => [fake_socket]} - Worker.push_to_socket(topics, "public", activity) + Streamer.push_to_socket(topics, "public", activity) Task.await(task) end @@ -243,9 +251,11 @@ test "it doesn't send to blocked users" do refute_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{ + fake_socket = %{ transport_pid: task.pid, - user: user + assigns: %{ + user: user + } } {:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"}) @@ -254,7 +264,7 @@ test "it doesn't send to blocked users" do "public" => [fake_socket] } - Worker.push_to_socket(topics, "public", activity) + Streamer.push_to_socket(topics, "public", activity) Task.await(task) end @@ -274,9 +284,11 @@ test "it doesn't send unwanted DMs to list" do refute_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{ + fake_socket = %{ transport_pid: task.pid, - user: user_a + assigns: %{ + user: user_a + } } {:ok, activity} = @@ -289,7 +301,7 @@ test "it doesn't send unwanted DMs to list" do "list:#{list.id}" => [fake_socket] } - Worker.handle_call({:stream, "list", activity}, self(), topics) + Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) Task.await(task) end @@ -306,9 +318,11 @@ test "it doesn't send unwanted private posts to list" do refute_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{ + fake_socket = %{ transport_pid: task.pid, - user: user_a + assigns: %{ + user: user_a + } } {:ok, activity} = @@ -321,12 +335,12 @@ test "it doesn't send unwanted private posts to list" do "list:#{list.id}" => [fake_socket] } - Worker.handle_call({:stream, "list", activity}, self(), topics) + Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) Task.await(task) end - test "it sends wanted private posts to list" do + test "it send wanted private posts to list" do user_a = insert(:user) user_b = insert(:user) @@ -340,9 +354,11 @@ test "it sends wanted private posts to list" do assert_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{ + fake_socket = %{ transport_pid: task.pid, - user: user_a + assigns: %{ + user: user_a + } } {:ok, activity} = @@ -351,12 +367,11 @@ test "it sends wanted private posts to list" do "visibility" => "private" }) - Streamer.add_socket( - "list:#{list.id}", - fake_socket - ) + topics = %{ + "list:#{list.id}" => [fake_socket] + } - Worker.handle_call({:stream, "list", activity}, self(), %{}) + Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) Task.await(task) end @@ -372,9 +387,11 @@ test "it doesn't send muted reblogs" do refute_receive {:text, _}, 1_000 end) - fake_socket = %StreamerSocket{ + fake_socket = %{ transport_pid: task.pid, - user: user1 + assigns: %{ + user: user1 + } } {:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"}) @@ -384,7 +401,7 @@ test "it doesn't send muted reblogs" do "public" => [fake_socket] } - Worker.push_to_socket(topics, "public", announce_activity) + Streamer.push_to_socket(topics, "public", announce_activity) Task.await(task) end @@ -400,8 +417,6 @@ test "it doesn't send posts from muted threads" do task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) - Process.sleep(4000) - Streamer.add_socket( "user", %{transport_pid: task.pid, assigns: %{user: user2}} @@ -413,6 +428,14 @@ test "it doesn't send posts from muted threads" do describe "direct streams" do setup do + GenServer.start(Streamer, %{}, name: Streamer) + + on_exit(fn -> + if pid = Process.whereis(Streamer) do + Process.exit(pid, :kill) + end + end) + :ok end @@ -457,8 +480,6 @@ test "it doesn't send conversation update to the 'direct' streamj when the last refute_receive {:text, _}, 4_000 end) - Process.sleep(1000) - Streamer.add_socket( "direct", %{transport_pid: task.pid, assigns: %{user: user}} @@ -500,8 +521,6 @@ test "it sends conversation update to the 'direct' stream when a message is dele assert last_status["id"] == to_string(create_activity.id) end) - Process.sleep(1000) - Streamer.add_socket( "direct", %{transport_pid: task.pid, assigns: %{user: user}} From e8120944d8c016a1aa8fcefe34b1f0cc9089ea4f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 16 Sep 2019 13:23:06 +0300 Subject: [PATCH 080/272] Fix signed fetch inclusion publisher test Oban branch changed `actor` to `actor_id` and this test was not adjusted for that --- test/web/activity_pub/publisher_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index c7d1d05aa..df03b4008 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -321,7 +321,7 @@ test "it returns inbox for messages involving single recipients in total" do assert called( Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ inbox: "https://domain.com/users/nick1/inbox", - actor: actor, + actor_id: actor.id, id: delete.data["id"] }) ) @@ -329,7 +329,7 @@ test "it returns inbox for messages involving single recipients in total" do assert called( Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ inbox: "https://domain2.com/users/nick1/inbox", - actor: actor, + actor_id: actor.id, id: delete.data["id"] }) ) From 96816ceaa25c21cec7677e75dcddd7ffb42d83c3 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 16 Sep 2019 17:03:37 +0700 Subject: [PATCH 081/272] Revert "Merge branch 'revert-4fabf83a' into 'develop'" This reverts commit fe7fd331263007e0fb2877ef7370a09a9704da36, reversing changes made to 4fabf83ad01352442906d79187aeab4c777f4df8. --- .gitignore | 4 + config/config.exs | 4 + lib/pleroma/activity/ir/topics.ex | 63 ++++ lib/pleroma/application.ex | 2 +- lib/pleroma/notification.ex | 6 +- lib/pleroma/web/activity_pub/activity_pub.ex | 48 +-- .../web/mastodon_api/websocket_handler.ex | 7 +- lib/pleroma/web/streamer.ex | 318 ------------------ lib/pleroma/web/streamer/ping.ex | 33 ++ lib/pleroma/web/streamer/state.ex | 68 ++++ lib/pleroma/web/streamer/streamer.ex | 55 +++ lib/pleroma/web/streamer/streamer_socket.ex | 31 ++ lib/pleroma/web/streamer/supervisor.ex | 33 ++ lib/pleroma/web/streamer/worker.ex | 220 ++++++++++++ lib/pleroma/web/views/streamer_view.ex | 66 ++++ mix.exs | 1 + mix.lock | 1 + test/activity/ir/topics_test.exs | 141 ++++++++ test/integration/mastodon_websocket_test.exs | 16 +- test/notification_test.exs | 11 +- test/support/conn_case.ex | 4 + test/support/data_case.ex | 4 + test/web/activity_pub/activity_pub_test.exs | 4 +- test/web/streamer/ping_test.exs | 36 ++ test/web/streamer/state_test.exs | 54 +++ test/web/{ => streamer}/streamer_test.exs | 105 +++--- 26 files changed, 888 insertions(+), 447 deletions(-) create mode 100644 lib/pleroma/activity/ir/topics.ex delete mode 100644 lib/pleroma/web/streamer.ex create mode 100644 lib/pleroma/web/streamer/ping.ex create mode 100644 lib/pleroma/web/streamer/state.ex create mode 100644 lib/pleroma/web/streamer/streamer.ex create mode 100644 lib/pleroma/web/streamer/streamer_socket.ex create mode 100644 lib/pleroma/web/streamer/supervisor.ex create mode 100644 lib/pleroma/web/streamer/worker.ex create mode 100644 lib/pleroma/web/views/streamer_view.ex create mode 100644 test/activity/ir/topics_test.exs create mode 100644 test/web/streamer/ping_test.exs create mode 100644 test/web/streamer/state_test.exs rename test/web/{ => streamer}/streamer_test.exs (86%) diff --git a/.gitignore b/.gitignore index 4e71a7df0..3b0c7d361 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ docs/generated_config.md # Code test coverage /cover /Elixir.*.coverdata + +.idea +pleroma.iml + diff --git a/config/config.exs b/config/config.exs index ab6e00c98..b1b98af93 100644 --- a/config/config.exs +++ b/config/config.exs @@ -331,6 +331,10 @@ follow_handshake_timeout: 500, sign_object_fetches: true +config :pleroma, :streamer, + workers: 3, + overflow_workers: 2 + config :pleroma, :user, deny_follow_blocked: true config :pleroma, :mrf_normalize_markup, scrub_policy: Pleroma.HTML.Scrubber.Default diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex new file mode 100644 index 000000000..010897abc --- /dev/null +++ b/lib/pleroma/activity/ir/topics.ex @@ -0,0 +1,63 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Activity.Ir.Topics do + alias Pleroma.Object + alias Pleroma.Web.ActivityPub.Visibility + + def get_activity_topics(activity) do + activity + |> Object.normalize() + |> generate_topics(activity) + |> List.flatten() + end + + defp generate_topics(%{data: %{"type" => "Answer"}}, _) do + [] + end + + defp generate_topics(object, activity) do + ["user", "list"] ++ visibility_tags(object, activity) + end + + defp visibility_tags(object, activity) do + case Visibility.get_visibility(activity) do + "public" -> + if activity.local do + ["public", "public:local"] + else + ["public"] + end + |> item_creation_tags(object, activity) + + "direct" -> + ["direct"] + + _ -> + [] + end + end + + defp item_creation_tags(tags, %{data: %{"type" => "Create"}} = object, activity) do + tags ++ hashtags_to_topics(object) ++ attachment_topics(object, activity) + end + + defp item_creation_tags(tags, _, _) do + tags + end + + defp hashtags_to_topics(%{data: %{"tag" => tags}}) do + tags + |> Enum.filter(&is_bitstring(&1)) + |> Enum.map(fn tag -> "hashtag:" <> tag end) + end + + defp hashtags_to_topics(_), do: [] + + defp attachment_topics(%{data: %{"attachment" => []}}, _act), do: [] + + defp attachment_topics(_object, %{local: true}), do: ["public:media", "public:local:media"] + + defp attachment_topics(_object, _act), do: ["public:media"] +end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 49094704b..3b37ce630 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -141,7 +141,7 @@ defp oauth_cleanup_enabled?, defp streamer_child(:test), do: [] defp streamer_child(_) do - [Pleroma.Web.Streamer] + [Pleroma.Web.Streamer.supervisor()] end defp oauth_cleanup_child(true), diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index b7c880c51..8012389ac 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -210,8 +210,10 @@ def create_notification(%Activity{} = activity, %User{} = user) do unless skip?(activity, user) do notification = %Notification{user_id: user.id, activity: activity} {:ok, notification} = Repo.insert(notification) - Streamer.stream("user", notification) - Streamer.stream("user:notification", notification) + + ["user", "user:notification"] + |> Streamer.stream(notification) + Push.send(notification) notification end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 41f6a0f1f..bc5ae7fbf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity + alias Pleroma.Activity.Ir.Topics alias Pleroma.Config alias Pleroma.Conversation alias Pleroma.Notification @@ -16,6 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.Streamer alias Pleroma.Web.WebFinger alias Pleroma.Workers.BackgroundWorker @@ -187,9 +189,7 @@ def stream_out_participations(participations) do participations |> Repo.preload(:user) - Enum.each(participations, fn participation -> - Pleroma.Web.Streamer.stream("participation", participation) - end) + Streamer.stream("participation", participations) end def stream_out_participations(%Object{data: %{"context" => context}}, user) do @@ -208,41 +208,15 @@ def stream_out_participations(%Object{data: %{"context" => context}}, user) do def stream_out_participations(_, _), do: :noop - def stream_out(activity) do - if activity.data["type"] in ["Create", "Announce", "Delete"] do - object = Object.normalize(activity) - # Do not stream out poll replies - unless object.data["type"] == "Answer" do - Pleroma.Web.Streamer.stream("user", activity) - Pleroma.Web.Streamer.stream("list", activity) + def stream_out(%Activity{data: %{"type" => data_type}} = activity) + when data_type in ["Create", "Announce", "Delete"] do + activity + |> Topics.get_activity_topics() + |> Streamer.stream(activity) + end - if get_visibility(activity) == "public" do - Pleroma.Web.Streamer.stream("public", activity) - - if activity.local do - Pleroma.Web.Streamer.stream("public:local", activity) - end - - if activity.data["type"] in ["Create"] do - object.data - |> Map.get("tag", []) - |> Enum.filter(fn tag -> is_bitstring(tag) end) - |> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end) - - if object.data["attachment"] != [] do - Pleroma.Web.Streamer.stream("public:media", activity) - - if activity.local do - Pleroma.Web.Streamer.stream("public:local:media", activity) - end - end - end - else - if get_visibility(activity) == "direct", - do: Pleroma.Web.Streamer.stream("direct", activity) - end - end - end + def stream_out(_activity) do + :noop end def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex index dbd3542ea..3c26eb406 100644 --- a/lib/pleroma/web/mastodon_api/websocket_handler.ex +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.Streamer @behaviour :cowboy_websocket @@ -24,7 +25,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do ] @anonymous_streams ["public", "public:local", "hashtag"] - # Handled by periodic keepalive in Pleroma.Web.Streamer. + # Handled by periodic keepalive in Pleroma.Web.Streamer.Ping. @timeout :infinity def init(%{qs: qs} = req, state) do @@ -65,7 +66,7 @@ def websocket_info(:subscribe, state) do }, topic #{state.topic}" ) - Pleroma.Web.Streamer.add_socket(state.topic, streamer_socket(state)) + Streamer.add_socket(state.topic, streamer_socket(state)) {:ok, state} end @@ -80,7 +81,7 @@ def terminate(reason, _req, state) do }, topic #{state.topic || "?"}: #{inspect(reason)}" ) - Pleroma.Web.Streamer.remove_socket(state.topic, streamer_socket(state)) + Streamer.remove_socket(state.topic, streamer_socket(state)) :ok end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex deleted file mode 100644 index 587c43f40..000000000 --- a/lib/pleroma/web/streamer.ex +++ /dev/null @@ -1,318 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Streamer do - use GenServer - require Logger - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.Conversation.Participation - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Visibility - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.NotificationView - - @keepalive_interval :timer.seconds(30) - - def start_link(_) do - GenServer.start_link(__MODULE__, %{}, name: __MODULE__) - end - - def add_socket(topic, socket) do - GenServer.cast(__MODULE__, %{action: :add, socket: socket, topic: topic}) - end - - def remove_socket(topic, socket) do - GenServer.cast(__MODULE__, %{action: :remove, socket: socket, topic: topic}) - end - - def stream(topic, item) do - GenServer.cast(__MODULE__, %{action: :stream, topic: topic, item: item}) - end - - def init(args) do - Process.send_after(self(), %{action: :ping}, @keepalive_interval) - - {:ok, args} - end - - def handle_info(%{action: :ping}, topics) do - topics - |> Map.values() - |> List.flatten() - |> Enum.each(fn socket -> - Logger.debug("Sending keepalive ping") - send(socket.transport_pid, {:text, ""}) - end) - - Process.send_after(self(), %{action: :ping}, @keepalive_interval) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "direct", item: item}, topics) do - recipient_topics = - User.get_recipients_from_activity(item) - |> Enum.map(fn %{id: id} -> "direct:#{id}" end) - - Enum.each(recipient_topics || [], fn user_topic -> - Logger.debug("Trying to push direct message to #{user_topic}\n\n") - push_to_socket(topics, user_topic, item) - end) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "participation", item: participation}, topics) do - user_topic = "direct:#{participation.user_id}" - Logger.debug("Trying to push a conversation participation to #{user_topic}\n\n") - - push_to_socket(topics, user_topic, participation) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "list", item: item}, topics) do - # filter the recipient list if the activity is not public, see #270. - recipient_lists = - case Visibility.is_public?(item) do - true -> - Pleroma.List.get_lists_from_activity(item) - - _ -> - Pleroma.List.get_lists_from_activity(item) - |> Enum.filter(fn list -> - owner = User.get_cached_by_id(list.user_id) - - Visibility.visible_for_user?(item, owner) - end) - end - - recipient_topics = - recipient_lists - |> Enum.map(fn %{id: id} -> "list:#{id}" end) - - Enum.each(recipient_topics || [], fn list_topic -> - Logger.debug("Trying to push message to #{list_topic}\n\n") - push_to_socket(topics, list_topic, item) - end) - - {:noreply, topics} - end - - def handle_cast( - %{action: :stream, topic: topic, item: %Notification{} = item}, - topics - ) - when topic in ["user", "user:notification"] do - topics - |> Map.get("#{topic}:#{item.user_id}", []) - |> Enum.each(fn socket -> - with %User{} = user <- User.get_cached_by_ap_id(socket.assigns[:user].ap_id), - true <- should_send?(user, item) do - send( - socket.transport_pid, - {:text, represent_notification(socket.assigns[:user], item)} - ) - end - end) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: "user", item: item}, topics) do - Logger.debug("Trying to push to users") - - recipient_topics = - User.get_recipients_from_activity(item) - |> Enum.map(fn %{id: id} -> "user:#{id}" end) - - Enum.each(recipient_topics, fn topic -> - push_to_socket(topics, topic, item) - end) - - {:noreply, topics} - end - - def handle_cast(%{action: :stream, topic: topic, item: item}, topics) do - Logger.debug("Trying to push to #{topic}") - Logger.debug("Pushing item to #{topic}") - push_to_socket(topics, topic, item) - {:noreply, topics} - end - - def handle_cast(%{action: :add, topic: topic, socket: socket}, sockets) do - topic = internal_topic(topic, socket) - sockets_for_topic = sockets[topic] || [] - sockets_for_topic = Enum.uniq([socket | sockets_for_topic]) - sockets = Map.put(sockets, topic, sockets_for_topic) - Logger.debug("Got new conn for #{topic}") - {:noreply, sockets} - end - - def handle_cast(%{action: :remove, topic: topic, socket: socket}, sockets) do - topic = internal_topic(topic, socket) - sockets_for_topic = sockets[topic] || [] - sockets_for_topic = List.delete(sockets_for_topic, socket) - sockets = Map.put(sockets, topic, sockets_for_topic) - Logger.debug("Removed conn for #{topic}") - {:noreply, sockets} - end - - def handle_cast(m, state) do - Logger.info("Unknown: #{inspect(m)}, #{inspect(state)}") - {:noreply, state} - end - - defp represent_update(%Activity{} = activity, %User{} = user) do - %{ - event: "update", - payload: - Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", - activity: activity, - for: user - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - defp represent_update(%Activity{} = activity) do - %{ - event: "update", - payload: - Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", - activity: activity - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - def represent_conversation(%Participation{} = participation) do - %{ - event: "conversation", - payload: - Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ - participation: participation, - for: participation.user - }) - |> Jason.encode!() - } - |> Jason.encode!() - end - - @spec represent_notification(User.t(), Notification.t()) :: binary() - defp represent_notification(%User{} = user, %Notification{} = notify) do - %{ - event: "notification", - payload: - NotificationView.render( - "show.json", - %{notification: notify, for: user} - ) - |> Jason.encode!() - } - |> Jason.encode!() - end - - defp should_send?(%User{} = user, %Activity{} = item) do - blocks = user.info.blocks || [] - mutes = user.info.mutes || [] - reblog_mutes = user.info.muted_reblogs || [] - domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) - - with parent when not is_nil(parent) <- Object.normalize(item), - true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), - true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), - %{host: item_host} <- URI.parse(item.actor), - %{host: parent_host} <- URI.parse(parent.data["actor"]), - false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), - false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), - true <- thread_containment(item, user), - false <- CommonAPI.thread_muted?(user, item) do - true - else - _ -> false - end - end - - defp should_send?(%User{} = user, %Notification{activity: activity}) do - should_send?(user, activity) - end - - def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do - Enum.each(topics[topic] || [], fn socket -> - # Get the current user so we have up-to-date blocks etc. - if socket.assigns[:user] do - user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) - - if should_send?(user, item) do - send(socket.transport_pid, {:text, represent_update(item, user)}) - end - else - send(socket.transport_pid, {:text, represent_update(item)}) - end - end) - end - - def push_to_socket(topics, topic, %Participation{} = participation) do - Enum.each(topics[topic] || [], fn socket -> - send(socket.transport_pid, {:text, represent_conversation(participation)}) - end) - end - - def push_to_socket(topics, topic, %Activity{ - data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id} - }) do - Enum.each(topics[topic] || [], fn socket -> - send( - socket.transport_pid, - {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()} - ) - end) - end - - def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop - - def push_to_socket(topics, topic, item) do - Enum.each(topics[topic] || [], fn socket -> - # Get the current user so we have up-to-date blocks etc. - if socket.assigns[:user] do - user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) - blocks = user.info.blocks || [] - mutes = user.info.mutes || [] - - with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), - true <- thread_containment(item, user) do - send(socket.transport_pid, {:text, represent_update(item, user)}) - end - else - send(socket.transport_pid, {:text, represent_update(item)}) - end - end) - end - - defp internal_topic(topic, socket) when topic in ~w[user user:notification direct] do - "#{topic}:#{socket.assigns[:user].id}" - end - - defp internal_topic(topic, _), do: topic - - @spec thread_containment(Activity.t(), User.t()) :: boolean() - defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true - - defp thread_containment(activity, user) do - if Config.get([:instance, :skip_thread_containment]) do - true - else - ActivityPub.contain_activity(activity, user) - end - end -end diff --git a/lib/pleroma/web/streamer/ping.ex b/lib/pleroma/web/streamer/ping.ex new file mode 100644 index 000000000..f77cbb95c --- /dev/null +++ b/lib/pleroma/web/streamer/ping.ex @@ -0,0 +1,33 @@ +defmodule Pleroma.Web.Streamer.Ping do + use GenServer + require Logger + + alias Pleroma.Web.Streamer.State + alias Pleroma.Web.Streamer.StreamerSocket + + @keepalive_interval :timer.seconds(30) + + def start_link(opts) do + ping_interval = Keyword.get(opts, :ping_interval, @keepalive_interval) + GenServer.start_link(__MODULE__, %{ping_interval: ping_interval}, name: __MODULE__) + end + + def init(%{ping_interval: ping_interval} = args) do + Process.send_after(self(), :ping, ping_interval) + {:ok, args} + end + + def handle_info(:ping, %{ping_interval: ping_interval} = state) do + State.get_sockets() + |> Map.values() + |> List.flatten() + |> Enum.each(fn %StreamerSocket{transport_pid: transport_pid} -> + Logger.debug("Sending keepalive ping") + send(transport_pid, {:text, ""}) + end) + + Process.send_after(self(), :ping, ping_interval) + + {:noreply, state} + end +end diff --git a/lib/pleroma/web/streamer/state.ex b/lib/pleroma/web/streamer/state.ex new file mode 100644 index 000000000..7b5199068 --- /dev/null +++ b/lib/pleroma/web/streamer/state.ex @@ -0,0 +1,68 @@ +defmodule Pleroma.Web.Streamer.State do + use GenServer + require Logger + + alias Pleroma.Web.Streamer.StreamerSocket + + def start_link(_) do + GenServer.start_link(__MODULE__, %{sockets: %{}}, name: __MODULE__) + end + + def add_socket(topic, socket) do + GenServer.call(__MODULE__, {:add, socket, topic}) + end + + def remove_socket(topic, socket) do + GenServer.call(__MODULE__, {:remove, socket, topic}) + end + + def get_sockets do + %{sockets: stream_sockets} = GenServer.call(__MODULE__, :get_state) + stream_sockets + end + + def init(init_arg) do + {:ok, init_arg} + end + + def handle_call(:get_state, _from, state) do + {:reply, state, state} + end + + def handle_call({:add, socket, topic}, _from, %{sockets: sockets} = state) do + internal_topic = internal_topic(topic, socket) + stream_socket = StreamerSocket.from_socket(socket) + + sockets_for_topic = + sockets + |> Map.get(internal_topic, []) + |> List.insert_at(0, stream_socket) + |> Enum.uniq() + + state = put_in(state, [:sockets, internal_topic], sockets_for_topic) + Logger.debug("Got new conn for #{topic}") + {:reply, state, state} + end + + def handle_call({:remove, socket, topic}, _from, %{sockets: sockets} = state) do + internal_topic = internal_topic(topic, socket) + stream_socket = StreamerSocket.from_socket(socket) + + sockets_for_topic = + sockets + |> Map.get(internal_topic, []) + |> List.delete(stream_socket) + + state = Kernel.put_in(state, [:sockets, internal_topic], sockets_for_topic) + {:reply, state, state} + end + + defp internal_topic(topic, socket) + when topic in ~w[user user:notification direct] do + "#{topic}:#{socket.assigns[:user].id}" + end + + defp internal_topic(topic, _) do + topic + end +end diff --git a/lib/pleroma/web/streamer/streamer.ex b/lib/pleroma/web/streamer/streamer.ex new file mode 100644 index 000000000..8cf719277 --- /dev/null +++ b/lib/pleroma/web/streamer/streamer.ex @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Streamer do + alias Pleroma.Web.Streamer.State + alias Pleroma.Web.Streamer.Worker + + @timeout 60_000 + @mix_env Mix.env() + + def add_socket(topic, socket) do + State.add_socket(topic, socket) + end + + def remove_socket(topic, socket) do + State.remove_socket(topic, socket) + end + + def get_sockets do + State.get_sockets() + end + + def stream(topics, items) do + if should_send?() do + Task.async(fn -> + :poolboy.transaction( + :streamer_worker, + &Worker.stream(&1, topics, items), + @timeout + ) + end) + end + end + + def supervisor, do: Pleroma.Web.Streamer.Supervisor + + defp should_send? do + handle_should_send(@mix_env) + end + + defp handle_should_send(:test) do + case Process.whereis(:streamer_worker) do + nil -> + false + + pid -> + Process.alive?(pid) + end + end + + defp handle_should_send(_) do + true + end +end diff --git a/lib/pleroma/web/streamer/streamer_socket.ex b/lib/pleroma/web/streamer/streamer_socket.ex new file mode 100644 index 000000000..f006c0306 --- /dev/null +++ b/lib/pleroma/web/streamer/streamer_socket.ex @@ -0,0 +1,31 @@ +defmodule Pleroma.Web.Streamer.StreamerSocket do + defstruct transport_pid: nil, user: nil + + alias Pleroma.User + alias Pleroma.Web.Streamer.StreamerSocket + + def from_socket(%{ + transport_pid: transport_pid, + assigns: %{user: nil} + }) do + %StreamerSocket{ + transport_pid: transport_pid + } + end + + def from_socket(%{ + transport_pid: transport_pid, + assigns: %{user: %User{} = user} + }) do + %StreamerSocket{ + transport_pid: transport_pid, + user: user + } + end + + def from_socket(%{transport_pid: transport_pid}) do + %StreamerSocket{ + transport_pid: transport_pid + } + end +end diff --git a/lib/pleroma/web/streamer/supervisor.ex b/lib/pleroma/web/streamer/supervisor.ex new file mode 100644 index 000000000..6afe19323 --- /dev/null +++ b/lib/pleroma/web/streamer/supervisor.ex @@ -0,0 +1,33 @@ +defmodule Pleroma.Web.Streamer.Supervisor do + use Supervisor + + def start_link(opts) do + Supervisor.start_link(__MODULE__, opts, name: __MODULE__) + end + + def init(args) do + children = [ + {Pleroma.Web.Streamer.State, args}, + {Pleroma.Web.Streamer.Ping, args}, + :poolboy.child_spec(:streamer_worker, poolboy_config()) + ] + + opts = [strategy: :one_for_one, name: Pleroma.Web.Streamer.Supervisor] + Supervisor.init(children, opts) + end + + defp poolboy_config do + opts = + Pleroma.Config.get(:streamer, + workers: 3, + overflow_workers: 2 + ) + + [ + {:name, {:local, :streamer_worker}}, + {:worker_module, Pleroma.Web.Streamer.Worker}, + {:size, opts[:workers]}, + {:max_overflow, opts[:overflow_workers]} + ] + end +end diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex new file mode 100644 index 000000000..5804508eb --- /dev/null +++ b/lib/pleroma/web/streamer/worker.ex @@ -0,0 +1,220 @@ +defmodule Pleroma.Web.Streamer.Worker do + use GenServer + + require Logger + + alias Pleroma.Activity + alias Pleroma.Config + alias Pleroma.Conversation.Participation + alias Pleroma.Notification + alias Pleroma.Object + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Streamer.State + alias Pleroma.Web.Streamer.StreamerSocket + alias Pleroma.Web.StreamerView + + def start_link(_) do + GenServer.start_link(__MODULE__, %{}, []) + end + + def init(init_arg) do + {:ok, init_arg} + end + + def stream(pid, topics, items) do + GenServer.call(pid, {:stream, topics, items}) + end + + def handle_call({:stream, topics, item}, _from, state) when is_list(topics) do + Enum.each(topics, fn t -> + do_stream(%{topic: t, item: item}) + end) + + {:reply, state, state} + end + + def handle_call({:stream, topic, items}, _from, state) when is_list(items) do + Enum.each(items, fn i -> + do_stream(%{topic: topic, item: i}) + end) + + {:reply, state, state} + end + + def handle_call({:stream, topic, item}, _from, state) do + do_stream(%{topic: topic, item: item}) + + {:reply, state, state} + end + + defp do_stream(%{topic: "direct", item: item}) do + recipient_topics = + User.get_recipients_from_activity(item) + |> Enum.map(fn %{id: id} -> "direct:#{id}" end) + + Enum.each(recipient_topics, fn user_topic -> + Logger.debug("Trying to push direct message to #{user_topic}\n\n") + push_to_socket(State.get_sockets(), user_topic, item) + end) + end + + defp do_stream(%{topic: "participation", item: participation}) do + user_topic = "direct:#{participation.user_id}" + Logger.debug("Trying to push a conversation participation to #{user_topic}\n\n") + + push_to_socket(State.get_sockets(), user_topic, participation) + end + + defp do_stream(%{topic: "list", item: item}) do + # filter the recipient list if the activity is not public, see #270. + recipient_lists = + case Visibility.is_public?(item) do + true -> + Pleroma.List.get_lists_from_activity(item) + + _ -> + Pleroma.List.get_lists_from_activity(item) + |> Enum.filter(fn list -> + owner = User.get_cached_by_id(list.user_id) + + Visibility.visible_for_user?(item, owner) + end) + end + + recipient_topics = + recipient_lists + |> Enum.map(fn %{id: id} -> "list:#{id}" end) + + Enum.each(recipient_topics, fn list_topic -> + Logger.debug("Trying to push message to #{list_topic}\n\n") + push_to_socket(State.get_sockets(), list_topic, item) + end) + end + + defp do_stream(%{topic: topic, item: %Notification{} = item}) + when topic in ["user", "user:notification"] do + State.get_sockets() + |> Map.get("#{topic}:#{item.user_id}", []) + |> Enum.each(fn %StreamerSocket{transport_pid: transport_pid, user: socket_user} -> + with %User{} = user <- User.get_cached_by_ap_id(socket_user.ap_id), + true <- should_send?(user, item) do + send(transport_pid, {:text, StreamerView.render("notification.json", socket_user, item)}) + end + end) + end + + defp do_stream(%{topic: "user", item: item}) do + Logger.debug("Trying to push to users") + + recipient_topics = + User.get_recipients_from_activity(item) + |> Enum.map(fn %{id: id} -> "user:#{id}" end) + + Enum.each(recipient_topics, fn topic -> + push_to_socket(State.get_sockets(), topic, item) + end) + end + + defp do_stream(%{topic: topic, item: item}) do + Logger.debug("Trying to push to #{topic}") + Logger.debug("Pushing item to #{topic}") + push_to_socket(State.get_sockets(), topic, item) + end + + defp should_send?(%User{} = user, %Activity{} = item) do + blocks = user.info.blocks || [] + mutes = user.info.mutes || [] + reblog_mutes = user.info.muted_reblogs || [] + domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) + + with parent when not is_nil(parent) <- Object.normalize(item), + true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), + true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), + %{host: item_host} <- URI.parse(item.actor), + %{host: parent_host} <- URI.parse(parent.data["actor"]), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), + true <- thread_containment(item, user), + false <- CommonAPI.thread_muted?(user, item) do + true + else + _ -> false + end + end + + defp should_send?(%User{} = user, %Notification{activity: activity}) 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)}) + end) + end + + def push_to_socket(topics, topic, %Activity{ + data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id} + }) do + Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} -> + send( + transport_pid, + {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()} + ) + end) + end + + def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop + + def push_to_socket(topics, topic, 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) + blocks = user.info.blocks || [] + mutes = user.info.mutes || [] + + with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), + true <- thread_containment(item, user) 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 + + @spec thread_containment(Activity.t(), User.t()) :: boolean() + defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true + + defp thread_containment(activity, user) do + if Config.get([:instance, :skip_thread_containment]) do + true + else + ActivityPub.contain_activity(activity, user) + end + end +end diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex new file mode 100644 index 000000000..b13030fa0 --- /dev/null +++ b/lib/pleroma/web/views/streamer_view.ex @@ -0,0 +1,66 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StreamerView do + use Pleroma.Web, :view + + alias Pleroma.Activity + alias Pleroma.Conversation.Participation + alias Pleroma.Notification + alias Pleroma.User + alias Pleroma.Web.MastodonAPI.NotificationView + + def render("update.json", %Activity{} = activity, %User{} = user) do + %{ + event: "update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "status.json", + activity: activity, + for: user + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + def render("notification.json", %User{} = user, %Notification{} = notify) do + %{ + event: "notification", + payload: + NotificationView.render( + "show.json", + %{notification: notify, for: user} + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + def render("update.json", %Activity{} = activity) do + %{ + event: "update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "status.json", + activity: activity + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + + def render("conversation.json", %Participation{} = participation) do + %{ + event: "conversation", + payload: + Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ + participation: participation, + for: participation.user + }) + |> Jason.encode!() + } + |> Jason.encode!() + end +end diff --git a/mix.exs b/mix.exs index f1e98585b..911ebad1d 100644 --- a/mix.exs +++ b/mix.exs @@ -144,6 +144,7 @@ defp deps do git: "https://git.pleroma.social/pleroma/http_signatures.git", ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"}, {:telemetry, "~> 0.3"}, + {:poolboy, "~> 1.5"}, {:prometheus_ex, "~> 3.0"}, {:prometheus_plugs, "~> 1.1"}, {:prometheus_phoenix, "~> 1.3"}, diff --git a/mix.lock b/mix.lock index 41697dd5c..0bf6a811e 100644 --- a/mix.lock +++ b/mix.lock @@ -73,6 +73,7 @@ "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, + "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, "postgrex": {:hex, :postgrex, "0.14.3", "5754dee2fdf6e9e508cbf49ab138df964278700b764177e8f3871e658b345a1e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.4.1", "1e96073b3ed7788053768fea779cbc896ddc3bdd9ba60687f2ad50b252ac87d6", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/test/activity/ir/topics_test.exs b/test/activity/ir/topics_test.exs new file mode 100644 index 000000000..e75f83586 --- /dev/null +++ b/test/activity/ir/topics_test.exs @@ -0,0 +1,141 @@ +defmodule Pleroma.Activity.Ir.TopicsTest do + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Activity.Ir.Topics + alias Pleroma.Object + + require Pleroma.Constants + + describe "poll answer" do + test "produce no topics" do + activity = %Activity{object: %Object{data: %{"type" => "Answer"}}} + + assert [] == Topics.get_activity_topics(activity) + end + end + + describe "non poll answer" do + test "always add user and list topics" do + activity = %Activity{object: %Object{data: %{"type" => "FooBar"}}} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "user") + assert Enum.member?(topics, "list") + end + end + + describe "public visibility" do + setup do + activity = %Activity{ + object: %Object{data: %{"type" => "Note"}}, + data: %{"to" => [Pleroma.Constants.as_public()]} + } + + {:ok, activity: activity} + end + + test "produces public topic", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public") + end + + test "local action produces public:local topic", %{activity: activity} do + activity = %{activity | local: true} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:local") + end + + test "non-local action does not produce public:local topic", %{activity: activity} do + activity = %{activity | local: false} + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "public:local") + end + end + + describe "public visibility create events" do + setup do + activity = %Activity{ + object: %Object{data: %{"type" => "Create", "attachment" => []}}, + data: %{"to" => [Pleroma.Constants.as_public()]} + } + + {:ok, activity: activity} + end + + test "with no attachments doesn't produce public:media topics", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "public:media") + refute Enum.member?(topics, "public:local:media") + end + + test "converts tags to hash tags", %{activity: %{object: %{data: data} = object} = activity} do + tagged_data = Map.put(data, "tag", ["foo", "bar"]) + activity = %{activity | object: %{object | data: tagged_data}} + + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "hashtag:foo") + assert Enum.member?(topics, "hashtag:bar") + end + + test "only converts strinngs to hash tags", %{ + activity: %{object: %{data: data} = object} = activity + } do + tagged_data = Map.put(data, "tag", [2]) + activity = %{activity | object: %{object | data: tagged_data}} + + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "hashtag:2") + end + end + + describe "public visibility create events with attachments" do + setup do + activity = %Activity{ + object: %Object{data: %{"type" => "Create", "attachment" => ["foo"]}}, + data: %{"to" => [Pleroma.Constants.as_public()]} + } + + {:ok, activity: activity} + end + + test "produce public:media topics", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:media") + end + + test "local produces public:local:media topics", %{activity: activity} do + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:local:media") + end + + test "non-local doesn't produce public:local:media topics", %{activity: activity} do + activity = %{activity | local: false} + + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "public:local:media") + end + end + + describe "non-public visibility" do + test "produces direct topic" do + activity = %Activity{object: %Object{data: %{"type" => "Note"}}, data: %{"to" => []}} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "direct") + refute Enum.member?(topics, "public") + refute Enum.member?(topics, "public:local") + refute Enum.member?(topics, "public:media") + refute Enum.member?(topics, "public:local:media") + end + end +end diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index 63bf73412..c04262808 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -11,7 +11,6 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do alias Pleroma.Integration.WebsocketClient alias Pleroma.Web.CommonAPI alias Pleroma.Web.OAuth - alias Pleroma.Web.Streamer @path Pleroma.Web.Endpoint.url() |> URI.parse() @@ -19,16 +18,6 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do |> Map.put(:path, "/api/v1/streaming") |> URI.to_string() - setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - end - def start_socket(qs \\ nil, headers \\ []) do path = case qs do @@ -53,12 +42,14 @@ test "requires authentication and a valid token for protected streams" do end) end + @tag needs_streamer: true test "allows public streams without authentication" do assert {:ok, _} = start_socket("?stream=public") assert {:ok, _} = start_socket("?stream=public:local") assert {:ok, _} = start_socket("?stream=hashtag&tag=lain") end + @tag needs_streamer: true test "receives well formatted events" do user = insert(:user) {:ok, _} = start_socket("?stream=public") @@ -103,6 +94,7 @@ test "accepts valid tokens", state do assert {:ok, _} = start_socket("?stream=user&access_token=#{state.token.token}") end + @tag needs_streamer: true test "accepts the 'user' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") @@ -111,6 +103,7 @@ test "accepts the 'user' stream", %{token: token} = _state do end) =~ ":badarg" end + @tag needs_streamer: true test "accepts the 'user:notification' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") @@ -119,6 +112,7 @@ test "accepts the 'user:notification' stream", %{token: token} = _state do end) =~ ":badarg" end + @tag needs_streamer: true test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}]) diff --git a/test/notification_test.exs b/test/notification_test.exs index 3be9db09b..3d2f9a8fc 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -69,16 +69,7 @@ test "does not create a notification for subscribed users if status is a reply" end describe "create_notification" do - setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - end - + @tag needs_streamer: true test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do user = insert(:user) task = Task.async(fn -> assert_receive {:text, _}, 4_000 end) diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index ec5892ff5..b39c70677 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -40,6 +40,10 @@ defmodule Pleroma.Web.ConnCase do Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) end + if tags[:needs_streamer] do + start_supervised(Pleroma.Web.Streamer.supervisor()) + end + {:ok, conn: Phoenix.ConnTest.build_conn()} end end diff --git a/test/support/data_case.ex b/test/support/data_case.ex index f3d98e7e3..17fa15214 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -39,6 +39,10 @@ defmodule Pleroma.DataCase do Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) end + if tags[:needs_streamer] do + start_supervised(Pleroma.Web.Streamer.supervisor()) + end + :ok end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index d0118fefa..4100108a5 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -38,9 +38,7 @@ test "it streams them out" do stream: fn _, _ -> nil end do ActivityPub.stream_out_participations(conversation.participations) - Enum.each(participations, fn participation -> - assert called(Pleroma.Web.Streamer.stream("participation", participation)) - end) + assert called(Pleroma.Web.Streamer.stream("participation", participations)) end end end diff --git a/test/web/streamer/ping_test.exs b/test/web/streamer/ping_test.exs new file mode 100644 index 000000000..3d52c00e4 --- /dev/null +++ b/test/web/streamer/ping_test.exs @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PingTest do + use Pleroma.DataCase + + import Pleroma.Factory + alias Pleroma.Web.Streamer + + setup do + start_supervised({Streamer.supervisor(), [ping_interval: 30]}) + + :ok + end + + describe "sockets" do + setup do + user = insert(:user) + {:ok, %{user: user}} + end + + test "it sends pings", %{user: user} do + task = + Task.async(fn -> + assert_receive {:text, received_event}, 40 + assert_receive {:text, received_event}, 40 + assert_receive {:text, received_event}, 40 + end) + + Streamer.add_socket("public", %{transport_pid: task.pid, assigns: %{user: user}}) + + Task.await(task) + end + end +end diff --git a/test/web/streamer/state_test.exs b/test/web/streamer/state_test.exs new file mode 100644 index 000000000..d1aeac541 --- /dev/null +++ b/test/web/streamer/state_test.exs @@ -0,0 +1,54 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StateTest do + use Pleroma.DataCase + + import Pleroma.Factory + alias Pleroma.Web.Streamer + alias Pleroma.Web.Streamer.StreamerSocket + + @moduletag needs_streamer: true + + describe "sockets" do + setup do + user = insert(:user) + user2 = insert(:user) + {:ok, %{user: user, user2: user2}} + end + + test "it can add a socket", %{user: user} do + Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) + + assert(%{"public" => [%StreamerSocket{transport_pid: 1}]} = Streamer.get_sockets()) + end + + test "it can add multiple sockets per user", %{user: user} do + Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) + Streamer.add_socket("public", %{transport_pid: 2, assigns: %{user: user}}) + + assert( + %{ + "public" => [ + %StreamerSocket{transport_pid: 2}, + %StreamerSocket{transport_pid: 1} + ] + } = Streamer.get_sockets() + ) + end + + test "it will not add a duplicate socket", %{user: user} do + Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) + Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) + + assert( + %{ + "activity" => [ + %StreamerSocket{transport_pid: 1} + ] + } = Streamer.get_sockets() + ) + end + end +end diff --git a/test/web/streamer_test.exs b/test/web/streamer/streamer_test.exs similarity index 86% rename from test/web/streamer_test.exs rename to test/web/streamer/streamer_test.exs index 96fa7645f..88847e20f 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -5,24 +5,20 @@ defmodule Pleroma.Web.StreamerTest do use Pleroma.DataCase + import Pleroma.Factory + alias Pleroma.List alias Pleroma.User alias Pleroma.Web.CommonAPI alias Pleroma.Web.Streamer - import Pleroma.Factory + alias Pleroma.Web.Streamer.StreamerSocket + alias Pleroma.Web.Streamer.Worker + @moduletag needs_streamer: true clear_config_all([:instance, :skip_thread_containment]) describe "user streams" do setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - user = insert(:user) notify = insert(:notification, user: user, activity: build(:note_activity)) {:ok, %{user: user, notify: notify}} @@ -125,11 +121,9 @@ test "it sends to public" do assert_receive {:text, _}, 4_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user - } + user: user } {:ok, activity} = CommonAPI.post(other_user, %{"status" => "Test"}) @@ -138,7 +132,7 @@ test "it sends to public" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) @@ -155,11 +149,9 @@ test "it sends to public" do assert received_event == expected_event end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user - } + user: user } {:ok, activity} = CommonAPI.delete(activity.id, other_user) @@ -168,7 +160,7 @@ test "it sends to public" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -189,9 +181,9 @@ test "it doesn't send to user if recipients invalid and thread containment is en ) task = Task.async(fn -> refute_receive {:text, _}, 1_000 end) - fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} topics = %{"public" => [fake_socket]} - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -211,9 +203,9 @@ test "it sends message if recipients invalid and thread containment is disabled" ) task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) - fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} topics = %{"public" => [fake_socket]} - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -233,9 +225,9 @@ test "it sends message if recipients invalid and thread containment is enabled b ) task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) - fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + fake_socket = %StreamerSocket{transport_pid: task.pid, user: user} topics = %{"public" => [fake_socket]} - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -251,11 +243,9 @@ test "it doesn't send to blocked users" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user - } + user: user } {:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"}) @@ -264,7 +254,7 @@ test "it doesn't send to blocked users" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", activity) + Worker.push_to_socket(topics, "public", activity) Task.await(task) end @@ -284,11 +274,9 @@ test "it doesn't send unwanted DMs to list" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user_a - } + user: user_a } {:ok, activity} = @@ -301,7 +289,7 @@ test "it doesn't send unwanted DMs to list" do "list:#{list.id}" => [fake_socket] } - Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) + Worker.handle_call({:stream, "list", activity}, self(), topics) Task.await(task) end @@ -318,11 +306,9 @@ test "it doesn't send unwanted private posts to list" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user_a - } + user: user_a } {:ok, activity} = @@ -335,12 +321,12 @@ test "it doesn't send unwanted private posts to list" do "list:#{list.id}" => [fake_socket] } - Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) + Worker.handle_call({:stream, "list", activity}, self(), topics) Task.await(task) end - test "it send wanted private posts to list" do + test "it sends wanted private posts to list" do user_a = insert(:user) user_b = insert(:user) @@ -354,11 +340,9 @@ test "it send wanted private posts to list" do assert_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user_a - } + user: user_a } {:ok, activity} = @@ -367,11 +351,12 @@ test "it send wanted private posts to list" do "visibility" => "private" }) - topics = %{ - "list:#{list.id}" => [fake_socket] - } + Streamer.add_socket( + "list:#{list.id}", + fake_socket + ) - Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) + Worker.handle_call({:stream, "list", activity}, self(), %{}) Task.await(task) end @@ -387,11 +372,9 @@ test "it doesn't send muted reblogs" do refute_receive {:text, _}, 1_000 end) - fake_socket = %{ + fake_socket = %StreamerSocket{ transport_pid: task.pid, - assigns: %{ - user: user1 - } + user: user1 } {:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"}) @@ -401,7 +384,7 @@ test "it doesn't send muted reblogs" do "public" => [fake_socket] } - Streamer.push_to_socket(topics, "public", announce_activity) + Worker.push_to_socket(topics, "public", announce_activity) Task.await(task) end @@ -417,6 +400,8 @@ test "it doesn't send posts from muted threads" do task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) + Process.sleep(4000) + Streamer.add_socket( "user", %{transport_pid: task.pid, assigns: %{user: user2}} @@ -428,14 +413,6 @@ test "it doesn't send posts from muted threads" do describe "direct streams" do setup do - GenServer.start(Streamer, %{}, name: Streamer) - - on_exit(fn -> - if pid = Process.whereis(Streamer) do - Process.exit(pid, :kill) - end - end) - :ok end @@ -480,6 +457,8 @@ test "it doesn't send conversation update to the 'direct' streamj when the last refute_receive {:text, _}, 4_000 end) + Process.sleep(1000) + Streamer.add_socket( "direct", %{transport_pid: task.pid, assigns: %{user: user}} @@ -521,6 +500,8 @@ test "it sends conversation update to the 'direct' stream when a message is dele assert last_status["id"] == to_string(create_activity.id) end) + Process.sleep(1000) + Streamer.add_socket( "direct", %{transport_pid: task.pid, assigns: %{user: user}} From 085d014f0859b3b3e5023c423ae0361ec6ed6c67 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 16 Sep 2019 19:26:00 +0700 Subject: [PATCH 082/272] Fix `Transmogrifier.upgrade_user_from_ap_id/1` --- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index acb3087d0..8461b666e 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -1050,7 +1050,7 @@ def upgrade_user_from_ap_id(ap_id) do with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id), {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id), already_ap <- User.ap_enabled?(user), - {:ok, user} <- user |> User.upgrade_changeset(data) |> User.update_and_set_cache() do + {:ok, user} <- user |> User.upgrade_changeset(data, true) |> User.update_and_set_cache() do unless already_ap do TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id}) end From d6ab78e610f16e97246ec9e83b3db72f04cf41e7 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 16 Sep 2019 21:48:01 +0700 Subject: [PATCH 083/272] Set `account_field_value_length` limit to 2048 by default --- config/config.exs | 2 +- config/description.exs | 4 ++-- docs/config.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.exs b/config/config.exs index b1b98af93..c7e0cf09f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -276,7 +276,7 @@ max_account_fields: 10, max_remote_account_fields: 20, account_field_name_length: 512, - account_field_value_length: 512, + account_field_value_length: 2048, external_user_synchronization: true config :pleroma, :markup, diff --git a/config/description.exs b/config/description.exs index be5eb0cc3..32d36d6d6 100644 --- a/config/description.exs +++ b/config/description.exs @@ -878,9 +878,9 @@ %{ key: :account_field_value_length, type: :integer, - description: "An account field value maximum length (default: 512)", + description: "An account field value maximum length (default: 2048)", suggestions: [ - 512 + 2048 ] }, %{ diff --git a/docs/config.md b/docs/config.md index 270d7fcea..3f37fa561 100644 --- a/docs/config.md +++ b/docs/config.md @@ -135,7 +135,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `max_account_fields`: The maximum number of custom fields in the user profile (default: `10`) * `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `20`) * `account_field_name_length`: An account field name maximum length (default: `512`) -* `account_field_value_length`: An account field value maximum length (default: `512`) +* `account_field_value_length`: An account field value maximum length (default: `2048`) * `external_user_synchronization`: Enabling following/followers counters synchronization for external users. From 56b60798c2282055089424f5dc6770a10876626b Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Mon, 16 Sep 2019 20:50:14 +0300 Subject: [PATCH 084/272] Code style fixes --- lib/pleroma/subscription_notification.ex | 72 +++++++++---------- .../views/subscription_notification_view.ex | 1 - 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/lib/pleroma/subscription_notification.ex b/lib/pleroma/subscription_notification.ex index 7ae25a7b1..9ce0c6598 100644 --- a/lib/pleroma/subscription_notification.ex +++ b/lib/pleroma/subscription_notification.ex @@ -56,7 +56,8 @@ def for_user_query(user, opts \\ []) do if opts[:with_muted] do query else - where(query, [n, a], a.actor not in ^user.info.muted_notifications) + query + |> where([n, a], a.actor not in ^user.info.muted_notifications) |> where([n, a], a.actor not in ^user.info.blocks) |> where( [n, a], @@ -88,9 +89,9 @@ def for_user(user, opts \\ %{}) do """ @spec for_user_since(Pleroma.User.t(), NaiveDateTime.t()) :: [t()] def for_user_since(user, date) do - from(n in for_user_query(user), - where: n.updated_at > ^date - ) + user + |> for_user_query() + |> where([n], n.updated_at > ^date) |> Repo.all() end @@ -112,10 +113,8 @@ def get(%{id: user_id} = _user, id) do preload: [activity: activity] ) - notification = Repo.one(query) - - case notification do - %{user_id: ^user_id} -> + case Repo.one(query) do + %{user_id: ^user_id} = notification -> {:ok, notification} _ -> @@ -137,10 +136,8 @@ def destroy_multiple(%{id: user_id} = _user, ids) do end def dismiss(%{id: user_id} = _user, id) do - notification = Repo.get(SubscriptionNotification, id) - - case notification do - %{user_id: ^user_id} -> + case Repo.get(SubscriptionNotification, id) do + %{user_id: ^user_id} = notification -> Repo.delete(notification) _ -> @@ -149,21 +146,24 @@ def dismiss(%{id: user_id} = _user, id) do end def create_notifications(%Activity{data: %{"to" => _, "type" => "Create"}} = activity) do - object = Object.normalize(activity) + case Object.normalize(activity) do + %{data: %{"type" => "Answer"}} -> + {:ok, []} - unless object && object.data["type"] == "Answer" do - users = get_notified_from_activity(activity) - notifications = Enum.map(users, fn user -> create_notification(activity, user) end) - {:ok, notifications} - else - {:ok, []} + _ -> + users = get_notified_from_activity(activity) + notifications = Enum.map(users, fn user -> create_notification(activity, user) end) + {:ok, notifications} end end def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity) when type in ["Like", "Announce", "Follow"] do - users = get_notified_from_activity(activity) - notifications = Enum.map(users, fn user -> create_notification(activity, user) end) + notifications = + activity + |> get_notified_from_activity() + |> Enum.map(&create_notification(activity, &1)) + {:ok, notifications} end @@ -188,12 +188,10 @@ def get_notified_from_activity( local_only ) when type in ["Create", "Like", "Announce", "Follow"] do - recipients = - [] - |> Utils.maybe_notify_subscribers(activity) - |> Enum.uniq() - - User.get_users_from_set(recipients, local_only) + [] + |> Utils.maybe_notify_subscribers(activity) + |> Enum.uniq() + |> User.get_users_from_set(local_only) end def get_notified_from_activity(_, _local_only), do: [] @@ -218,12 +216,12 @@ def skip?(:self, activity, user) do def skip?( :followers, - activity, + %{data: %{"actor" => actor}}, %{info: %{notification_settings: %{"followers" => false}}} = user ) do - actor = activity.data["actor"] - follower = User.get_cached_by_ap_id(actor) - User.following?(follower, user) + actor + |> User.get_cached_by_ap_id() + |> User.following?(user) end def skip?( @@ -252,14 +250,10 @@ def skip?( !User.following?(user, followed) end - def skip?(:recently_followed, %{data: %{"type" => "Follow"}} = activity, user) do - actor = activity.data["actor"] - - SubscriptionNotification.for_user(user) - |> Enum.any?(fn - %{activity: %{data: %{"type" => "Follow", "actor" => ^actor}}} -> true - _ -> false - end) + def skip?(:recently_followed, %{data: %{"type" => "Follow", "actor" => actor}}, user) do + user + |> SubscriptionNotification.for_user() + |> Enum.any?(&match?(%{activity: %{data: %{"type" => "Follow", "actor" => ^actor}}}, &1)) end def skip?(_, _, _), do: false diff --git a/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex b/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex index c6f0b5064..83d2b647f 100644 --- a/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionNotificationView do use Pleroma.Web, :view alias Pleroma.Activity - # alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView From 6042e21b25885f9c3214d3296d9d2fdf35ad58ea Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Mon, 16 Sep 2019 21:59:49 +0300 Subject: [PATCH 085/272] Move subscription notifications to a separate controller --- .../controllers/mastodon_api_controller.ex | 48 ---- lib/pleroma/web/mastodon_api/mastodon_api.ex | 10 - lib/pleroma/web/pleroma_api/pleroma_api.ex | 40 +++ .../subscription_notification_controller.ex | 59 +++++ .../views/subscription_notification_view.ex | 4 +- lib/pleroma/web/router.ex | 33 +-- .../mastodon_api_controller_test.exs | 192 -------------- ...scription_notification_controller_test.exs | 234 ++++++++++++++++++ 8 files changed, 343 insertions(+), 277 deletions(-) create mode 100644 lib/pleroma/web/pleroma_api/pleroma_api.ex create mode 100644 lib/pleroma/web/pleroma_api/subscription_notification_controller.ex rename lib/pleroma/web/{mastodon_api => pleroma_api}/views/subscription_notification_view.ex (93%) create mode 100644 test/web/pleroma_api/subscription_notification_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index eefdb8c06..060137b80 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -23,7 +23,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.Stats - alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.ActivityPub.ActivityPub @@ -40,7 +39,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.ReportView alias Pleroma.Web.MastodonAPI.ScheduledActivityView alias Pleroma.Web.MastodonAPI.StatusView - alias Pleroma.Web.MastodonAPI.SubscriptionNotificationView alias Pleroma.Web.MediaProxy alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization @@ -727,28 +725,6 @@ def notifications(%{assigns: %{user: user}} = conn, params) do |> render("index.json", %{notifications: notifications, for: user}) end - def subscription_notifications(%{assigns: %{user: user}} = conn, params) do - notifications = MastodonAPI.get_subscription_notifications(user, params) - - conn - |> add_link_headers(:subscription_notifications, notifications) - |> put_view(SubscriptionNotificationView) - |> render("index.json", %{notifications: notifications, for: user}) - end - - def get_subscription_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do - with {:ok, notification} <- SubscriptionNotification.get(user, id) do - conn - |> put_view(SubscriptionNotificationView) - |> render("show.json", %{subscription_notification: notification, for: user}) - else - {:error, reason} -> - conn - |> put_status(:forbidden) - |> json(%{"error" => reason}) - end - end - def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do with {:ok, notification} <- Notification.get(user, id) do conn @@ -767,11 +743,6 @@ def clear_notifications(%{assigns: %{user: user}} = conn, _params) do json(conn, %{}) end - def clear_subscription_notifications(%{assigns: %{user: user}} = conn, _params) do - SubscriptionNotification.clear(user) - json(conn, %{}) - end - def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do with {:ok, _notif} <- Notification.dismiss(user, id) do json(conn, %{}) @@ -783,30 +754,11 @@ def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _para end end - def dismiss_subscription_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do - with {:ok, _notif} <- SubscriptionNotification.dismiss(user, id) do - json(conn, %{}) - else - {:error, reason} -> - conn - |> put_status(:forbidden) - |> json(%{"error" => reason}) - end - end - def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do Notification.destroy_multiple(user, ids) json(conn, %{}) end - def destroy_multiple_subscription_notifications( - %{assigns: %{user: user}} = conn, - %{"ids" => ids} = _params - ) do - SubscriptionNotification.destroy_multiple(user, ids) - json(conn, %{}) - end - def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do id = List.wrap(id) q = from(u in User, where: u.id in ^id) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 6751e24d8..ac01d1ff3 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -10,7 +10,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do alias Pleroma.Notification alias Pleroma.Pagination alias Pleroma.ScheduledActivity - alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -63,15 +62,6 @@ def get_notifications(user, params \\ %{}) do |> Pagination.fetch_paginated(params) end - def get_subscription_notifications(user, params \\ %{}) do - options = cast_params(params) - - user - |> SubscriptionNotification.for_user_query(options) - |> restrict(:exclude_types, options) - |> Pagination.fetch_paginated(params) - end - def get_scheduled_activities(user, params \\ %{}) do user |> ScheduledActivity.for_user_query() diff --git a/lib/pleroma/web/pleroma_api/pleroma_api.ex b/lib/pleroma/web/pleroma_api/pleroma_api.ex new file mode 100644 index 000000000..480964845 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/pleroma_api.ex @@ -0,0 +1,40 @@ +defmodule Pleroma.Web.PleromaAPI.PleromaAPI do + import Ecto.Query + import Ecto.Changeset + + alias Pleroma.Activity + alias Pleroma.Pagination + alias Pleroma.SubscriptionNotification + + def get_subscription_notifications(user, params \\ %{}) do + options = cast_params(params) + + user + |> SubscriptionNotification.for_user_query(options) + |> restrict(:exclude_types, options) + |> Pagination.fetch_paginated(params) + end + + defp cast_params(params) do + param_types = %{ + exclude_types: {:array, :string}, + reblogs: :boolean, + with_muted: :boolean + } + + changeset = cast({%{}, param_types}, params, Map.keys(param_types)) + changeset.changes + end + + defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]}) do + ap_types = + mastodon_types + |> Enum.map(&Activity.from_mastodon_notification_type/1) + |> Enum.filter(& &1) + + query + |> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data)) + end + + defp restrict(query, _, _), do: query +end diff --git a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex new file mode 100644 index 000000000..bfc2631dd --- /dev/null +++ b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex @@ -0,0 +1,59 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + + alias Pleroma.SubscriptionNotification + alias Pleroma.Web.PleromaAPI.PleromaAPI + alias Pleroma.Web.PleromaAPI.SubscriptionNotificationView + + def list(%{assigns: %{user: user}} = conn, params) do + notifications = PleromaAPI.get_subscription_notifications(user, params) + + conn + |> add_link_headers(notifications) + |> put_view(SubscriptionNotificationView) + |> render("index.json", %{notifications: notifications, for: user}) + end + + def get(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do + with {:ok, notification} <- SubscriptionNotification.get(user, id) do + conn + |> put_view(SubscriptionNotificationView) + |> render("show.json", %{subscription_notification: notification, for: user}) + else + {:error, reason} -> + conn + |> put_status(:forbidden) + |> json(%{"error" => reason}) + end + end + + def clear(%{assigns: %{user: user}} = conn, _params) do + SubscriptionNotification.clear(user) + json(conn, %{}) + end + + def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do + with {:ok, _notif} <- SubscriptionNotification.dismiss(user, id) do + json(conn, %{}) + else + {:error, reason} -> + conn + |> put_status(:forbidden) + |> json(%{"error" => reason}) + end + end + + def destroy_multiple( + %{assigns: %{user: user}} = conn, + %{"ids" => ids} = _params + ) do + SubscriptionNotification.destroy_multiple(user, ids) + json(conn, %{}) + end +end diff --git a/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex similarity index 93% rename from lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex rename to lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex index 83d2b647f..d7f7f4c5a 100644 --- a/lib/pleroma/web/mastodon_api/views/subscription_notification_view.ex +++ b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex @@ -2,15 +2,15 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.MastodonAPI.SubscriptionNotificationView do +defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationView do use Pleroma.Web, :view alias Pleroma.Activity alias Pleroma.User alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView - alias Pleroma.Web.MastodonAPI.SubscriptionNotificationView alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.PleromaAPI.SubscriptionNotificationView def render("index.json", %{notifications: notifications, for: user}) do safe_render_many(notifications, SubscriptionNotificationView, "show.json", %{for: user}) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 409fc9eca..05891b6c0 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -268,6 +268,14 @@ defmodule Pleroma.Web.Router do pipe_through(:oauth_read) get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) get("/conversations/:id", PleromaAPIController, :conversation) + + scope "/subscription_notifications" do + post("/clear", SubscriptionNotificationController, :clear) + post("/dismiss", SubscriptionNotificationController, :dismiss) + delete("/destroy_multiple", SubscriptionNotificationController, :destroy_multiple) + get("/", SubscriptionNotificationController, :list) + get("/id", SubscriptionNotificationController, :get) + end end scope [] do @@ -302,38 +310,13 @@ defmodule Pleroma.Web.Router do post("/notifications/clear", MastodonAPIController, :clear_notifications) - post( - "/notifications/subscription/clear", - MastodonAPIController, - :clear_subscription_notifications - ) - post("/notifications/dismiss", MastodonAPIController, :dismiss_notification) - post( - "/notifications/subscription/dismiss", - MastodonAPIController, - :dismiss_subscription_notification - ) - get("/notifications", MastodonAPIController, :notifications) - get("/notifications/subscription", MastodonAPIController, :subscription_notifications) get("/notifications/:id", MastodonAPIController, :get_notification) - get( - "/notifications/subscription/:id", - MastodonAPIController, - :get_subscription_notification - ) - delete("/notifications/destroy_multiple", MastodonAPIController, :destroy_multiple) - delete( - "/notifications/subscription/destroy_multiple", - MastodonAPIController, - :destroy_multiple_subscription_notifications - ) - get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses) get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 1d2d9e134..fb04748bb 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -13,7 +13,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Pleroma.Object alias Pleroma.Repo alias Pleroma.ScheduledActivity - alias Pleroma.SubscriptionNotification alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -1275,197 +1274,6 @@ test "see notifications after muting user with notifications and with_muted para end end - describe "subscription_notifications" do - setup do - user = insert(:user) - subscriber = insert(:user) - - User.subscribe(subscriber, user) - - {:ok, %{user: user, subscriber: subscriber}} - end - - test "list of notifications", %{conn: conn, user: user, subscriber: subscriber} do - status_text = "Hello" - {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) - - conn = - conn - |> assign(:user, subscriber) - |> get("/api/v1/notifications/subscription") - - assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) - assert response == status_text - end - - test "getting a single notification", %{conn: conn, user: user, subscriber: subscriber} do - status_text = "Hello" - - {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) - [notification] = Repo.all(SubscriptionNotification) - - conn = - conn - |> assign(:user, subscriber) - |> get("/api/v1/notifications/subscription/#{notification.id}") - - assert %{"status" => %{"content" => response}} = json_response(conn, 200) - assert response == status_text - end - - test "dismissing a single notification also deletes it", %{ - conn: conn, - user: user, - subscriber: subscriber - } do - status_text = "Hello" - {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) - - [notification] = Repo.all(SubscriptionNotification) - - conn = - conn - |> assign(:user, subscriber) - |> post("/api/v1/notifications/subscription/dismiss", %{"id" => notification.id}) - - assert %{} = json_response(conn, 200) - - assert Repo.all(SubscriptionNotification) == [] - end - - test "clearing all notifications also deletes them", %{ - conn: conn, - user: user, - subscriber: subscriber - } do - status_text1 = "Hello" - status_text2 = "Hello again" - {:ok, _activity1} = CommonAPI.post(user, %{"status" => status_text1}) - {:ok, _activity2} = CommonAPI.post(user, %{"status" => status_text2}) - - conn = - conn - |> assign(:user, subscriber) - |> post("/api/v1/notifications/subscription/clear") - - assert %{} = json_response(conn, 200) - - conn = - build_conn() - |> assign(:user, subscriber) - |> get("/api/v1/notifications/subscription") - - assert json_response(conn, 200) == [] - - assert Repo.all(SubscriptionNotification) == [] - end - - test "paginates notifications using min_id, since_id, max_id, and limit", %{ - conn: conn, - user: user, - subscriber: subscriber - } do - {:ok, activity1} = CommonAPI.post(user, %{"status" => "Hello 1"}) - {:ok, activity2} = CommonAPI.post(user, %{"status" => "Hello 2"}) - {:ok, activity3} = CommonAPI.post(user, %{"status" => "Hello 3"}) - {:ok, activity4} = CommonAPI.post(user, %{"status" => "Hello 4"}) - - notification1_id = - Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() - - notification2_id = - Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() - - notification3_id = - Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() - - notification4_id = - Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() - - conn = assign(conn, :user, subscriber) - - # min_id - conn_res = - get(conn, "/api/v1/notifications/subscription?limit=2&min_id=#{notification1_id}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - - # since_id - conn_res = - get(conn, "/api/v1/notifications/subscription?limit=2&since_id=#{notification1_id}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - - # max_id - conn_res = - get(conn, "/api/v1/notifications/subscription?limit=2&max_id=#{notification4_id}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - end - - test "destroy multiple", %{conn: conn, user: user1, subscriber: user2} do - # mutual subscription - User.subscribe(user1, user2) - - {:ok, activity1} = CommonAPI.post(user1, %{"status" => "Hello 1"}) - {:ok, activity2} = CommonAPI.post(user1, %{"status" => "World 1"}) - {:ok, activity3} = CommonAPI.post(user2, %{"status" => "Hello 2"}) - {:ok, activity4} = CommonAPI.post(user2, %{"status" => "World 2"}) - - notification1_id = - Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() - - notification2_id = - Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() - - notification3_id = - Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() - - notification4_id = - Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() - - conn = assign(conn, :user, user1) - - conn_res = get(conn, "/api/v1/notifications/subscription") - - result = json_response(conn_res, 200) - - Enum.each(result, fn %{"id" => id} -> - assert id in [notification3_id, notification4_id] - end) - - conn2 = assign(conn, :user, user2) - - conn_res = get(conn2, "/api/v1/notifications/subscription") - - result = json_response(conn_res, 200) - - Enum.each(result, fn %{"id" => id} -> - assert id in [notification1_id, notification2_id] - end) - - conn_destroy = - delete(conn, "/api/v1/notifications/subscription/destroy_multiple", %{ - "ids" => [notification3_id, notification4_id] - }) - - assert json_response(conn_destroy, 200) == %{} - - conn_res = get(conn2, "/api/v1/notifications/subscription") - - result = json_response(conn_res, 200) - - Enum.each(result, fn %{"id" => id} -> - assert id in [notification1_id, notification2_id] - end) - - assert length(Repo.all(SubscriptionNotification)) == 2 - end - end - describe "reblogging" do test "reblogs and returns the reblogged status", %{conn: conn} do activity = insert(:note_activity) diff --git a/test/web/pleroma_api/subscription_notification_controller_test.exs b/test/web/pleroma_api/subscription_notification_controller_test.exs new file mode 100644 index 000000000..ee495f112 --- /dev/null +++ b/test/web/pleroma_api/subscription_notification_controller_test.exs @@ -0,0 +1,234 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Repo + alias Pleroma.SubscriptionNotification + alias Pleroma.User + alias Pleroma.Web.CommonAPI + import Pleroma.Factory + import Tesla.Mock + + setup do + mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + clear_config([:instance, :public]) + clear_config([:rich_media, :enabled]) + + describe "subscription_notifications" do + setup do + user = insert(:user) + subscriber = insert(:user) + + User.subscribe(subscriber, user) + + {:ok, %{user: user, subscriber: subscriber}} + end + + test "list of notifications", %{conn: conn, user: user, subscriber: subscriber} do + status_text = "Hello" + {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) + path = subscription_notification_path(conn, :list) + + conn = + conn + |> assign(:user, subscriber) + |> get(path) + + assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) + assert response == status_text + end + + test "getting a single notification", %{conn: conn, user: user, subscriber: subscriber} do + status_text = "Hello" + + {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) + [notification] = Repo.all(SubscriptionNotification) + + path = subscription_notification_path(conn, :get, id: notification.id) + + conn = + conn + |> assign(:user, subscriber) + |> get(path) + + assert %{"status" => %{"content" => response}} = json_response(conn, 200) + assert response == status_text + end + + test "dismissing a single notification also deletes it", %{ + conn: conn, + user: user, + subscriber: subscriber + } do + status_text = "Hello" + {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) + + [notification] = Repo.all(SubscriptionNotification) + + conn = + conn + |> assign(:user, subscriber) + |> post(subscription_notification_path(conn, :dismiss), %{"id" => notification.id}) + + assert %{} = json_response(conn, 200) + + assert Repo.all(SubscriptionNotification) == [] + end + + test "clearing all notifications also deletes them", %{ + conn: conn, + user: user, + subscriber: subscriber + } do + status_text1 = "Hello" + status_text2 = "Hello again" + {:ok, _activity1} = CommonAPI.post(user, %{"status" => status_text1}) + {:ok, _activity2} = CommonAPI.post(user, %{"status" => status_text2}) + + conn = + conn + |> assign(:user, subscriber) + |> post(subscription_notification_path(conn, :clear)) + + assert %{} = json_response(conn, 200) + + conn = + build_conn() + |> assign(:user, subscriber) + |> get(subscription_notification_path(conn, :list)) + + assert json_response(conn, 200) == [] + + assert Repo.all(SubscriptionNotification) == [] + end + + test "paginates notifications using min_id, since_id, max_id, and limit", %{ + conn: conn, + user: user, + subscriber: subscriber + } do + {:ok, activity1} = CommonAPI.post(user, %{"status" => "Hello 1"}) + {:ok, activity2} = CommonAPI.post(user, %{"status" => "Hello 2"}) + {:ok, activity3} = CommonAPI.post(user, %{"status" => "Hello 3"}) + {:ok, activity4} = CommonAPI.post(user, %{"status" => "Hello 4"}) + + notification1_id = + Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() + + notification2_id = + Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() + + notification3_id = + Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() + + notification4_id = + Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() + + conn = assign(conn, :user, subscriber) + + # min_id + conn_res = + get( + conn, + subscription_notification_path(conn, :list, %{ + "limit" => 2, + "min_id" => notification1_id + }) + ) + + result = json_response(conn_res, 200) + assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + + # since_id + conn_res = + get( + conn, + subscription_notification_path(conn, :list, %{ + "limit" => 2, + "since_id" => notification1_id + }) + ) + + result = json_response(conn_res, 200) + assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + + # max_id + conn_res = + get( + conn, + subscription_notification_path(conn, :list, %{ + "limit" => 2, + "max_id" => notification4_id + }) + ) + + result = json_response(conn_res, 200) + assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + end + + test "destroy multiple", %{conn: conn, user: user1, subscriber: user2} do + # mutual subscription + User.subscribe(user1, user2) + + {:ok, activity1} = CommonAPI.post(user1, %{"status" => "Hello 1"}) + {:ok, activity2} = CommonAPI.post(user1, %{"status" => "World 1"}) + {:ok, activity3} = CommonAPI.post(user2, %{"status" => "Hello 2"}) + {:ok, activity4} = CommonAPI.post(user2, %{"status" => "World 2"}) + + notification1_id = + Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() + + notification2_id = + Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() + + notification3_id = + Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() + + notification4_id = + Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() + + conn = assign(conn, :user, user1) + + conn_res = get(conn, subscription_notification_path(conn, :list)) + + result = json_response(conn_res, 200) + + Enum.each(result, fn %{"id" => id} -> + assert id in [notification3_id, notification4_id] + end) + + conn2 = assign(conn, :user, user2) + + conn_res = get(conn2, subscription_notification_path(conn, :list)) + + result = json_response(conn_res, 200) + + Enum.each(result, fn %{"id" => id} -> + assert id in [notification1_id, notification2_id] + end) + + conn_destroy = + delete(conn, subscription_notification_path(conn, :destroy_multiple), %{ + "ids" => [notification3_id, notification4_id] + }) + + assert json_response(conn_destroy, 200) == %{} + + conn_res = get(conn2, subscription_notification_path(conn, :list)) + + result = json_response(conn_res, 200) + + Enum.each(result, fn %{"id" => id} -> + assert id in [notification1_id, notification2_id] + end) + + assert length(Repo.all(SubscriptionNotification)) == 2 + end + end +end From a21584556f2c3edb90db3c58ba2a4829a7e220c1 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 17 Sep 2019 13:04:43 +0300 Subject: [PATCH 086/272] Update oban to 0.8.1 This version uses a different locking mechanism, which gets rid of `WARNING: you don't own a lock of type ShareLock` log spam --- lib/pleroma/flake_id.ex | 2 +- mix.exs | 2 +- mix.lock | 8 ++++---- priv/repo/migrations/20190917100019_update_oban.exs | 11 +++++++++++ 4 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 priv/repo/migrations/20190917100019_update_oban.exs diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex index 47d61ca5f..042cf8659 100644 --- a/lib/pleroma/flake_id.ex +++ b/lib/pleroma/flake_id.ex @@ -14,7 +14,7 @@ defmodule Pleroma.FlakeId do @type t :: binary - @behaviour Ecto.Type + use Ecto.Type use GenServer require Logger alias __MODULE__ diff --git a/mix.exs b/mix.exs index 911ebad1d..230f90244 100644 --- a/mix.exs +++ b/mix.exs @@ -101,7 +101,7 @@ defp deps do {:phoenix_ecto, "~> 4.0"}, {:ecto_sql, "~> 3.1"}, {:postgrex, ">= 0.13.5"}, - {:oban, "~> 0.7"}, + {:oban, "~> 0.8.1"}, {:quantum, "~> 2.3"}, {:gettext, "~> 0.15"}, {:comeonin, "~> 4.1.1"}, diff --git a/mix.lock b/mix.lock index 0bf6a811e..547ff6be6 100644 --- a/mix.lock +++ b/mix.lock @@ -21,8 +21,8 @@ "decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.3.6", "ce1d0675e10a5bb46b007549362bd3f5f08908843957687d8484fe7f37466b19", [:mix], [], "hexpm"}, - "ecto": {:hex, :ecto, "3.1.4", "69d852da7a9f04ede725855a35ede48d158ca11a404fe94f8b2fb3b2162cd3c9", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, - "ecto_sql": {:hex, :ecto_sql, "3.1.3", "2c536139190492d9de33c5fefac7323c5eaaa82e1b9bf93482a14649042f7cd9", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, + "ecto": {:hex, :ecto, "3.2.0", "940e2598813f205223d60c78d66e514afe1db5167ed8075510a59e496619cfb5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, + "ecto_sql": {:hex, :ecto_sql, "3.2.0", "751cea597e8deb616084894dd75cbabfdbe7255ff01e8c058ca13f0353a3921b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"}, "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"}, "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, @@ -60,7 +60,7 @@ "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"}, - "oban": {:hex, :oban, "0.7.1", "171bdd1b69c1a4a839f8c768f5e962fc22d1de1513d459fb6b8e0cbd34817a9a", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, + "oban": {:hex, :oban, "0.8.1", "4bbf62eb1829f856d69aeb5069ac7036afe07db8221a17de2a9169cc7a58a318", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"}, "phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, @@ -74,7 +74,7 @@ "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, - "postgrex": {:hex, :postgrex, "0.14.3", "5754dee2fdf6e9e508cbf49ab138df964278700b764177e8f3871e658b345a1e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, + "postgrex": {:hex, :postgrex, "0.15.1", "23ce3417de70f4c0e9e7419ad85bdabcc6860a6925fe2c6f3b1b5b1e8e47bf2f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.4.1", "1e96073b3ed7788053768fea779cbc896ddc3bdd9ba60687f2ad50b252ac87d6", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/priv/repo/migrations/20190917100019_update_oban.exs b/priv/repo/migrations/20190917100019_update_oban.exs new file mode 100644 index 000000000..157dc54f9 --- /dev/null +++ b/priv/repo/migrations/20190917100019_update_oban.exs @@ -0,0 +1,11 @@ +defmodule Pleroma.Repo.Migrations.UpdateOban do + use Ecto.Migration + + def up do + Oban.Migrations.up(version: 4) + end + + def down do + Oban.Migrations.down(version: 2) + end +end From 450bf7a63c39c2301d5985448a867e77f1dfe3b3 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Fri, 13 Sep 2019 17:37:30 +0300 Subject: [PATCH 087/272] Mastodon API: Add a setting to hide follow/follower count from the user view (`hide_follows_count` and `hide_followers_count`) --- CHANGELOG.md | 1 + docs/api/differences_in_mastoapi_responses.md | 4 +++ lib/pleroma/user/info.ex | 14 ++++++-- .../web/activity_pub/views/user_view.ex | 32 +++++++++++-------- .../controllers/mastodon_api_controller.ex | 2 ++ .../web/mastodon_api/views/account_view.ex | 14 ++++++-- .../web/activity_pub/views/user_view_test.exs | 24 ++++++++++++-- .../update_credentials_test.exs | 16 ++++++++++ .../mastodon_api/views/account_view_test.exs | 31 ++++++++++++++++-- 9 files changed, 117 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eb72c002..7dfa477b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,6 +94,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: added `/auth/password` endpoint for password reset with rate limit. - Mastodon API: /api/v1/accounts/:id/statuses now supports nicknames or user id - Mastodon API: Improve support for the user profile custom fields +- Mastodon API: follower/following counters are nullified when `hide_follows`/`hide_followers` and `hide_follows_count`/`hide_followers_count` are set - Admin API: Return users' tags when querying reports - Admin API: Return avatar and display name when querying users - Admin API: Allow querying user by ID diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 9b32baf3a..3c7f5dad7 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -50,6 +50,8 @@ Has these additional fields under the `pleroma` object: - `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated - `hide_followers`: boolean, true when the user has follower hiding enabled - `hide_follows`: boolean, true when the user has follow hiding enabled +- `hide_followers_count`: boolean, true when the user has follower stat hiding enabled +- `hide_follows_count`: boolean, true when the user has follow stat hiding enabled - `settings_store`: A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials` - `chat_token`: The token needed for Pleroma chat. Only returned in `verify_credentials` - `deactivated`: boolean, true when the user is deactivated @@ -112,6 +114,8 @@ Additional parameters can be added to the JSON body/Form data: - `no_rich_text` - if true, html tags are stripped from all statuses requested from the API - `hide_followers` - if true, user's followers will be hidden - `hide_follows` - if true, user's follows will be hidden +- `hide_followers_count` - if true, user's follower count will be hidden +- `hide_follows_count` - if true, user's follow count will be hidden - `hide_favorites` - if true, user's favorites timeline will be hidden - `show_role` - if true, user's role (e.g admin, moderator) will be exposed to anyone in the API - `default_scope` - the scope returned under `privacy` key in Source subentity diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 151e025de..b150a57cd 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -41,6 +41,8 @@ defmodule Pleroma.User.Info do field(:topic, :string, default: nil) field(:hub, :string, default: nil) field(:salmon, :string, default: nil) + field(:hide_followers_count, :boolean, default: false) + field(:hide_follows_count, :boolean, default: false) field(:hide_followers, :boolean, default: false) field(:hide_follows, :boolean, default: false) field(:hide_favorites, :boolean, default: true) @@ -262,6 +264,8 @@ def remote_user_creation(info, params) do :salmon, :hide_followers, :hide_follows, + :hide_followers_count, + :hide_follows_count, :follower_count, :fields, :following_count @@ -281,7 +285,9 @@ def user_upgrade(info, params, remote? \\ false) do :following_count, :hide_follows, :fields, - :hide_followers + :hide_followers, + :hide_followers_count, + :hide_follows_count ]) |> validate_fields(remote?) end @@ -295,6 +301,8 @@ def profile_update(info, params) do :banner, :hide_follows, :hide_followers, + :hide_followers_count, + :hide_follows_count, :hide_favorites, :background, :show_role, @@ -458,7 +466,9 @@ def follow_information_update(info, params) do :hide_followers, :hide_follows, :follower_count, - :following_count + :following_count, + :hide_followers_count, + :hide_follows_count ]) end end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 7be734b26..164b973d0 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -118,30 +118,34 @@ def render("user.json", %{user: user}) do end def render("following.json", %{user: user, page: page} = opts) do - showing = (opts[:for] && opts[:for] == user) || !user.info.hide_follows + showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_follows + showing_count = showing_items || !user.info.hide_follows_count + query = User.get_friends_query(user) query = from(user in query, select: [:ap_id]) following = Repo.all(query) total = - if showing do + if showing_count do length(following) else 0 end - collection(following, "#{user.ap_id}/following", page, showing, total) + collection(following, "#{user.ap_id}/following", page, showing_items, total) |> Map.merge(Utils.make_json_ld_header()) end def render("following.json", %{user: user} = opts) do - showing = (opts[:for] && opts[:for] == user) || !user.info.hide_follows + showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_follows + showing_count = showing_items || !user.info.hide_follows_count + query = User.get_friends_query(user) query = from(user in query, select: [:ap_id]) following = Repo.all(query) total = - if showing do + if showing_count do length(following) else 0 @@ -152,7 +156,7 @@ def render("following.json", %{user: user} = opts) do "type" => "OrderedCollection", "totalItems" => total, "first" => - if showing do + if showing_items do collection(following, "#{user.ap_id}/following", 1, !user.info.hide_follows) else "#{user.ap_id}/following?page=1" @@ -162,32 +166,34 @@ def render("following.json", %{user: user} = opts) do end def render("followers.json", %{user: user, page: page} = opts) do - showing = (opts[:for] && opts[:for] == user) || !user.info.hide_followers + showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_followers + showing_count = showing_items || !user.info.hide_followers_count query = User.get_followers_query(user) query = from(user in query, select: [:ap_id]) followers = Repo.all(query) total = - if showing do + if showing_count do length(followers) else 0 end - collection(followers, "#{user.ap_id}/followers", page, showing, total) + collection(followers, "#{user.ap_id}/followers", page, showing_items, total) |> Map.merge(Utils.make_json_ld_header()) end def render("followers.json", %{user: user} = opts) do - showing = (opts[:for] && opts[:for] == user) || !user.info.hide_followers + showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_followers + showing_count = showing_items || !user.info.hide_followers_count query = User.get_followers_query(user) query = from(user in query, select: [:ap_id]) followers = Repo.all(query) total = - if showing do + if showing_count do length(followers) else 0 @@ -198,8 +204,8 @@ def render("followers.json", %{user: user} = opts) do "type" => "OrderedCollection", "totalItems" => total, "first" => - if showing do - collection(followers, "#{user.ap_id}/followers", 1, showing, total) + if showing_items do + collection(followers, "#{user.ap_id}/followers", 1, showing_items, total) else "#{user.ap_id}/followers?page=1" end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 060137b80..1beb4bcf2 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -147,6 +147,8 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do [ :no_rich_text, :locked, + :hide_followers_count, + :hide_follows_count, :hide_followers, :hide_follows, :hide_favorites, diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 169116d0d..195dd124b 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -74,10 +74,18 @@ defp do_render("account.json", %{user: user} = opts) do user_info = User.get_cached_user_info(user) following_count = - ((!user.info.hide_follows or opts[:for] == user) && user_info.following_count) || 0 + if !user.info.hide_follows_count or !user.info.hide_follows or opts[:for] == user do + user_info.following_count + else + 0 + end followers_count = - ((!user.info.hide_followers or opts[:for] == user) && user_info.follower_count) || 0 + if !user.info.hide_followers_count or !user.info.hide_followers or opts[:for] == user do + user_info.follower_count + else + 0 + end bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"] @@ -138,6 +146,8 @@ defp do_render("account.json", %{user: user} = opts) do pleroma: %{ confirmation_pending: user_info.confirmation_pending, tags: user.tags, + hide_followers_count: user.info.hide_followers_count, + hide_follows_count: user.info.hide_follows_count, hide_followers: user.info.hide_followers, hide_follows: user.info.hide_follows, hide_favorites: user.info.hide_favorites, diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index fb7fd9e79..2b4a04afd 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -105,10 +105,20 @@ test "sets totalItems to zero when followers are hidden" do other_user = insert(:user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) - info = Map.put(user.info, :hide_followers, true) + info = Map.merge(user.info, %{hide_followers_count: true, hide_followers: true}) user = Map.put(user, :info, info) assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user}) end + + test "sets correct totalItems when followers are hidden but the follower counter is not" do + user = insert(:user) + other_user = insert(:user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) + info = Map.merge(user.info, %{hide_followers_count: false, hide_followers: true}) + user = Map.put(user, :info, info) + assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) + end end describe "following" do @@ -117,9 +127,19 @@ test "sets totalItems to zero when follows are hidden" do other_user = insert(:user) {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) - info = Map.put(user.info, :hide_follows, true) + info = Map.merge(user.info, %{hide_follows_count: true, hide_follows: true}) user = Map.put(user, :info, info) assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user}) end + + test "sets correct totalItems when follows are hidden but the follow counter is not" do + user = insert(:user) + other_user = insert(:user) + {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) + assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) + info = Map.merge(user.info, %{hide_follows_count: false, hide_follows: true}) + user = Map.put(user, :info, info) + assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) + end end end diff --git a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs index 87ee82050..89d4ca37e 100644 --- a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs @@ -128,6 +128,22 @@ test "updates the user's hide_followers status", %{conn: conn} do assert user["pleroma"]["hide_followers"] == true end + test "updates the user's hide_followers_count and hide_follows_count", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{ + hide_followers_count: "true", + hide_follows_count: "true" + }) + + assert user = json_response(conn, 200) + assert user["pleroma"]["hide_followers_count"] == true + assert user["pleroma"]["hide_follows_count"] == true + end + test "updates the user's skip_thread_containment option", %{conn: conn} do user = insert(:user) diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 1d8b28339..8ff6751d3 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -79,6 +79,8 @@ test "Represent a user account" do hide_favorites: true, hide_followers: false, hide_follows: false, + hide_followers_count: false, + hide_follows_count: false, relationship: %{}, skip_thread_containment: false } @@ -147,6 +149,8 @@ test "Represent a Service(bot) account" do hide_favorites: true, hide_followers: false, hide_follows: false, + hide_followers_count: false, + hide_follows_count: false, relationship: %{}, skip_thread_containment: false } @@ -318,6 +322,8 @@ test "represent an embedded relationship" do hide_favorites: true, hide_followers: false, hide_follows: false, + hide_followers_count: false, + hide_follows_count: false, relationship: %{ id: to_string(user.id), following: false, @@ -361,8 +367,16 @@ test "sanitizes display names" do end describe "hiding follows/following" do - test "shows when follows/following are hidden and sets follower/following count to 0" do - user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do + info = %{ + hide_followers: true, + hide_followers_count: true, + hide_follows: true, + hide_follows_count: true + } + + user = insert(:user, info: info) + other_user = insert(:user) {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) @@ -370,6 +384,19 @@ test "shows when follows/following are hidden and sets follower/following count assert %{ followers_count: 0, following_count: 0, + pleroma: %{hide_follows_count: true, hide_followers_count: true} + } = AccountView.render("account.json", %{user: user}) + end + + test "shows when follows/followers are hidden" do + user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + other_user = insert(:user) + {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{ + followers_count: 1, + following_count: 1, pleroma: %{hide_follows: true, hide_followers: true} } = AccountView.render("account.json", %{user: user}) end From 2688b876abf5ebd48d18e460eee7db992f984f5a Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 13:42:28 +0000 Subject: [PATCH 088/272] Apply suggestion to lib/pleroma/web/pleroma_api/subscription_notification_controller.ex --- .../web/pleroma_api/subscription_notification_controller.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex index bfc2631dd..d5da92946 100644 --- a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex +++ b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex @@ -9,7 +9,6 @@ defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationController do alias Pleroma.SubscriptionNotification alias Pleroma.Web.PleromaAPI.PleromaAPI - alias Pleroma.Web.PleromaAPI.SubscriptionNotificationView def list(%{assigns: %{user: user}} = conn, params) do notifications = PleromaAPI.get_subscription_notifications(user, params) From c0f776faecfa91ed755760975da12b546ca89317 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 13:42:36 +0000 Subject: [PATCH 089/272] Apply suggestion to lib/pleroma/web/pleroma_api/subscription_notification_controller.ex --- .../web/pleroma_api/subscription_notification_controller.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex index d5da92946..fff307b4e 100644 --- a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex +++ b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex @@ -15,7 +15,6 @@ def list(%{assigns: %{user: user}} = conn, params) do conn |> add_link_headers(notifications) - |> put_view(SubscriptionNotificationView) |> render("index.json", %{notifications: notifications, for: user}) end From f9be517c7f3e63cfaaca871a4458cbf7c8a6a3f4 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 13:42:40 +0000 Subject: [PATCH 090/272] Apply suggestion to lib/pleroma/web/pleroma_api/subscription_notification_controller.ex --- .../web/pleroma_api/subscription_notification_controller.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex index fff307b4e..969ce0179 100644 --- a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex +++ b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex @@ -20,9 +20,7 @@ def list(%{assigns: %{user: user}} = conn, params) do def get(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do with {:ok, notification} <- SubscriptionNotification.get(user, id) do - conn - |> put_view(SubscriptionNotificationView) - |> render("show.json", %{subscription_notification: notification, for: user}) + render(conn, "show.json", %{subscription_notification: notification, for: user}) else {:error, reason} -> conn From a81f80233d63d98a0de7b57def76275182d5477e Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 13:43:10 +0000 Subject: [PATCH 091/272] Apply suggestion to lib/pleroma/web/router.ex --- lib/pleroma/web/router.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 05891b6c0..1fff94b38 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -274,7 +274,7 @@ defmodule Pleroma.Web.Router do post("/dismiss", SubscriptionNotificationController, :dismiss) delete("/destroy_multiple", SubscriptionNotificationController, :destroy_multiple) get("/", SubscriptionNotificationController, :list) - get("/id", SubscriptionNotificationController, :get) + get("/:id", SubscriptionNotificationController, :get) end end From 015597c2abbd9a78df76903bb2c3d229bf11e958 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 13:43:15 +0000 Subject: [PATCH 092/272] Apply suggestion to test/web/pleroma_api/subscription_notification_controller_test.exs --- .../pleroma_api/subscription_notification_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/pleroma_api/subscription_notification_controller_test.exs b/test/web/pleroma_api/subscription_notification_controller_test.exs index ee495f112..781d27ead 100644 --- a/test/web/pleroma_api/subscription_notification_controller_test.exs +++ b/test/web/pleroma_api/subscription_notification_controller_test.exs @@ -50,7 +50,7 @@ test "getting a single notification", %{conn: conn, user: user, subscriber: subs {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) [notification] = Repo.all(SubscriptionNotification) - path = subscription_notification_path(conn, :get, id: notification.id) + path = subscription_notification_path(conn, :get, notification) conn = conn From a76168e743c3dd193db6ebca029f287da9edd290 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 16:44:41 +0300 Subject: [PATCH 093/272] Cleanup PleromaAPIController --- .../web/pleroma_api/pleroma_api_controller.ex | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index 246b351dc..d17ccf84d 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -9,7 +9,6 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do alias Pleroma.Conversation.Participation alias Pleroma.Notification - alias Pleroma.SubscriptionNotification alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.NotificationView @@ -87,29 +86,4 @@ def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) d |> render("index.json", %{notifications: notifications, for: user}) end end - - def delete_subscription_notification(%{assigns: %{user: user}} = conn, %{ - "id" => notification_id - }) do - with {:ok, notification} <- SubscriptionNotification.dismiss(user, notification_id) do - conn - |> put_view(NotificationView) - |> render("show.json", %{notification: notification, for: user}) - else - {:error, message} -> - conn - |> put_status(:bad_request) - |> json(%{"error" => message}) - end - end - - def read_subscription_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do - with notifications <- SubscriptionNotification.clear_up_to(user, max_id) do - notifications = Enum.take(notifications, 80) - - conn - |> put_view(NotificationView) - |> render("index.json", %{notifications: notifications, for: user}) - end - end end From 7d1773bc6b01caad8666ef07a9b2f2ac326fd0cd Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 16:48:24 +0300 Subject: [PATCH 094/272] Rename SubscriptionNotificationController list and get actions to index and show --- .../subscription_notification_controller.ex | 4 ++-- lib/pleroma/web/router.ex | 4 ++-- ...bscription_notification_controller_test.exs | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex index 969ce0179..fa8307668 100644 --- a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex +++ b/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex @@ -10,7 +10,7 @@ defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationController do alias Pleroma.SubscriptionNotification alias Pleroma.Web.PleromaAPI.PleromaAPI - def list(%{assigns: %{user: user}} = conn, params) do + def index(%{assigns: %{user: user}} = conn, params) do notifications = PleromaAPI.get_subscription_notifications(user, params) conn @@ -18,7 +18,7 @@ def list(%{assigns: %{user: user}} = conn, params) do |> render("index.json", %{notifications: notifications, for: user}) end - def get(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do + def show(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do with {:ok, notification} <- SubscriptionNotification.get(user, id) do render(conn, "show.json", %{subscription_notification: notification, for: user}) else diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 1fff94b38..502c67e74 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -273,8 +273,8 @@ defmodule Pleroma.Web.Router do post("/clear", SubscriptionNotificationController, :clear) post("/dismiss", SubscriptionNotificationController, :dismiss) delete("/destroy_multiple", SubscriptionNotificationController, :destroy_multiple) - get("/", SubscriptionNotificationController, :list) - get("/:id", SubscriptionNotificationController, :get) + get("/", SubscriptionNotificationController, :index) + get("/:id", SubscriptionNotificationController, :show) end end diff --git a/test/web/pleroma_api/subscription_notification_controller_test.exs b/test/web/pleroma_api/subscription_notification_controller_test.exs index 781d27ead..c6a71732d 100644 --- a/test/web/pleroma_api/subscription_notification_controller_test.exs +++ b/test/web/pleroma_api/subscription_notification_controller_test.exs @@ -33,7 +33,7 @@ defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationControllerTest do test "list of notifications", %{conn: conn, user: user, subscriber: subscriber} do status_text = "Hello" {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) - path = subscription_notification_path(conn, :list) + path = subscription_notification_path(conn, :index) conn = conn @@ -50,7 +50,7 @@ test "getting a single notification", %{conn: conn, user: user, subscriber: subs {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) [notification] = Repo.all(SubscriptionNotification) - path = subscription_notification_path(conn, :get, notification) + path = subscription_notification_path(conn, :show, notification) conn = conn @@ -101,7 +101,7 @@ test "clearing all notifications also deletes them", %{ conn = build_conn() |> assign(:user, subscriber) - |> get(subscription_notification_path(conn, :list)) + |> get(subscription_notification_path(conn, :index)) assert json_response(conn, 200) == [] @@ -136,7 +136,7 @@ test "paginates notifications using min_id, since_id, max_id, and limit", %{ conn_res = get( conn, - subscription_notification_path(conn, :list, %{ + subscription_notification_path(conn, :index, %{ "limit" => 2, "min_id" => notification1_id }) @@ -149,7 +149,7 @@ test "paginates notifications using min_id, since_id, max_id, and limit", %{ conn_res = get( conn, - subscription_notification_path(conn, :list, %{ + subscription_notification_path(conn, :index, %{ "limit" => 2, "since_id" => notification1_id }) @@ -162,7 +162,7 @@ test "paginates notifications using min_id, since_id, max_id, and limit", %{ conn_res = get( conn, - subscription_notification_path(conn, :list, %{ + subscription_notification_path(conn, :index, %{ "limit" => 2, "max_id" => notification4_id }) @@ -195,7 +195,7 @@ test "destroy multiple", %{conn: conn, user: user1, subscriber: user2} do conn = assign(conn, :user, user1) - conn_res = get(conn, subscription_notification_path(conn, :list)) + conn_res = get(conn, subscription_notification_path(conn, :index)) result = json_response(conn_res, 200) @@ -205,7 +205,7 @@ test "destroy multiple", %{conn: conn, user: user1, subscriber: user2} do conn2 = assign(conn, :user, user2) - conn_res = get(conn2, subscription_notification_path(conn, :list)) + conn_res = get(conn2, subscription_notification_path(conn, :index)) result = json_response(conn_res, 200) @@ -220,7 +220,7 @@ test "destroy multiple", %{conn: conn, user: user1, subscriber: user2} do assert json_response(conn_destroy, 200) == %{} - conn_res = get(conn2, subscription_notification_path(conn, :list)) + conn_res = get(conn2, subscription_notification_path(conn, :index)) result = json_response(conn_res, 200) From e9f69a3eb7f17ae8c2890972851de1139983ce3d Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 16:52:23 +0300 Subject: [PATCH 095/272] Move pleroma_api controllers into controllers sub-folders --- .../web/pleroma_api/{ => controllers}/pleroma_api_controller.ex | 0 .../{ => controllers}/subscription_notification_controller.ex | 0 .../pleroma_api/{ => controllers}/pleroma_api_controller_test.exs | 0 .../subscription_notification_controller_test.exs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename lib/pleroma/web/pleroma_api/{ => controllers}/pleroma_api_controller.ex (100%) rename lib/pleroma/web/pleroma_api/{ => controllers}/subscription_notification_controller.ex (100%) rename test/web/pleroma_api/{ => controllers}/pleroma_api_controller_test.exs (100%) rename test/web/pleroma_api/{ => controllers}/subscription_notification_controller_test.exs (100%) diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex similarity index 100% rename from lib/pleroma/web/pleroma_api/pleroma_api_controller.ex rename to lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex diff --git a/lib/pleroma/web/pleroma_api/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex similarity index 100% rename from lib/pleroma/web/pleroma_api/subscription_notification_controller.ex rename to lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex diff --git a/test/web/pleroma_api/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs similarity index 100% rename from test/web/pleroma_api/pleroma_api_controller_test.exs rename to test/web/pleroma_api/controllers/pleroma_api_controller_test.exs diff --git a/test/web/pleroma_api/subscription_notification_controller_test.exs b/test/web/pleroma_api/controllers/subscription_notification_controller_test.exs similarity index 100% rename from test/web/pleroma_api/subscription_notification_controller_test.exs rename to test/web/pleroma_api/controllers/subscription_notification_controller_test.exs From 9fa2586abd915342095574f05358642412db0f04 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 17 Sep 2019 17:44:10 +0300 Subject: [PATCH 096/272] Refactor SubscriptionNotificationView --- .../subscription_notification_controller.ex | 20 +++++++++++++++++-- .../views/subscription_notification_view.ex | 9 +++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex index fa8307668..37c2222de 100644 --- a/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex @@ -7,11 +7,16 @@ defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationController do import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + alias Pleroma.Activity alias Pleroma.SubscriptionNotification + alias Pleroma.User alias Pleroma.Web.PleromaAPI.PleromaAPI def index(%{assigns: %{user: user}} = conn, params) do - notifications = PleromaAPI.get_subscription_notifications(user, params) + notifications = + user + |> PleromaAPI.get_subscription_notifications(params) + |> Enum.map(&build_notification_data/1) conn |> add_link_headers(notifications) @@ -20,7 +25,10 @@ def index(%{assigns: %{user: user}} = conn, params) do def show(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do with {:ok, notification} <- SubscriptionNotification.get(user, id) do - render(conn, "show.json", %{subscription_notification: notification, for: user}) + render(conn, "show.json", %{ + subscription_notification: build_notification_data(notification), + for: user + }) else {:error, reason} -> conn @@ -52,4 +60,12 @@ def destroy_multiple( SubscriptionNotification.destroy_multiple(user, ids) json(conn, %{}) end + + defp build_notification_data(%{activity: %{data: data}} = notification) do + %{ + notification: notification, + actor: User.get_cached_by_ap_id(data["actor"]), + parent_activity: Activity.get_create_by_object_ap_id(data["object"]) + } + end end diff --git a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex index d7f7f4c5a..0eccbcbb9 100644 --- a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex +++ b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationView do use Pleroma.Web, :view alias Pleroma.Activity - alias Pleroma.User alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.StatusView @@ -17,11 +16,13 @@ def render("index.json", %{notifications: notifications, for: user}) do end def render("show.json", %{ - subscription_notification: %{activity: activity} = notification, + subscription_notification: %{ + notification: %{activity: activity} = notification, + actor: actor, + parent_activity: parent_activity + }, for: user }) do - actor = User.get_cached_by_ap_id(activity.data["actor"]) - parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"]) mastodon_type = Activity.mastodon_notification_type(activity) response = %{ From 80c5c3495bdd7939e576c8746a959f3f89f44042 Mon Sep 17 00:00:00 2001 From: Steven Fuchs Date: Tue, 17 Sep 2019 14:44:52 +0000 Subject: [PATCH 097/272] remove remaining errors from tests --- lib/pleroma/application.ex | 53 ++++++++++++++------ lib/pleroma/web/streamer/state.ex | 18 +++++-- test/integration/mastodon_websocket_test.exs | 16 ++++-- 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 3b37ce630..dabce771d 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -43,23 +43,9 @@ def start(_type, _args) do hackney_pool_children() ++ [ Pleroma.Stats, - {Oban, Pleroma.Config.get(Oban)}, - %{ - id: :web_push_init, - start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, - restart: :temporary - }, - %{ - id: :federator_init, - start: {Task, :start_link, [&Pleroma.Web.Federator.init/0]}, - restart: :temporary - }, - %{ - id: :internal_fetch_init, - start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]}, - restart: :temporary - } + {Oban, Pleroma.Config.get(Oban)} ] ++ + task_children(@env) ++ oauth_cleanup_child(oauth_cleanup_enabled?()) ++ streamer_child(@env) ++ chat_child(@env, chat_enabled?()) ++ @@ -163,4 +149,39 @@ defp hackney_pool_children do :hackney_pool.child_spec(pool, options) end end + + defp task_children(:test) do + [ + %{ + id: :web_push_init, + start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, + restart: :temporary + }, + %{ + id: :federator_init, + start: {Task, :start_link, [&Pleroma.Web.Federator.init/0]}, + restart: :temporary + } + ] + end + + defp task_children(_) do + [ + %{ + id: :web_push_init, + start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, + restart: :temporary + }, + %{ + id: :federator_init, + start: {Task, :start_link, [&Pleroma.Web.Federator.init/0]}, + restart: :temporary + }, + %{ + id: :internal_fetch_init, + start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]}, + restart: :temporary + } + ] + end end diff --git a/lib/pleroma/web/streamer/state.ex b/lib/pleroma/web/streamer/state.ex index 7b5199068..c48752d95 100644 --- a/lib/pleroma/web/streamer/state.ex +++ b/lib/pleroma/web/streamer/state.ex @@ -4,16 +4,18 @@ defmodule Pleroma.Web.Streamer.State do alias Pleroma.Web.Streamer.StreamerSocket + @env Mix.env() + def start_link(_) do GenServer.start_link(__MODULE__, %{sockets: %{}}, name: __MODULE__) end def add_socket(topic, socket) do - GenServer.call(__MODULE__, {:add, socket, topic}) + GenServer.call(__MODULE__, {:add, topic, socket}) end def remove_socket(topic, socket) do - GenServer.call(__MODULE__, {:remove, socket, topic}) + do_remove_socket(@env, topic, socket) end def get_sockets do @@ -29,7 +31,7 @@ def handle_call(:get_state, _from, state) do {:reply, state, state} end - def handle_call({:add, socket, topic}, _from, %{sockets: sockets} = state) do + def handle_call({:add, topic, socket}, _from, %{sockets: sockets} = state) do internal_topic = internal_topic(topic, socket) stream_socket = StreamerSocket.from_socket(socket) @@ -44,7 +46,7 @@ def handle_call({:add, socket, topic}, _from, %{sockets: sockets} = state) do {:reply, state, state} end - def handle_call({:remove, socket, topic}, _from, %{sockets: sockets} = state) do + def handle_call({:remove, topic, socket}, _from, %{sockets: sockets} = state) do internal_topic = internal_topic(topic, socket) stream_socket = StreamerSocket.from_socket(socket) @@ -57,6 +59,14 @@ def handle_call({:remove, socket, topic}, _from, %{sockets: sockets} = state) do {:reply, state, state} end + defp do_remove_socket(:test, _, _) do + :ok + end + + defp do_remove_socket(_env, topic, socket) do + GenServer.call(__MODULE__, {:remove, topic, socket}) + end + defp internal_topic(topic, socket) when topic in ~w[user user:notification direct] do "#{topic}:#{socket.assigns[:user].id}" diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index c04262808..d02a3cc4d 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -18,6 +18,11 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do |> Map.put(:path, "/api/v1/streaming") |> URI.to_string() + setup_all do + start_supervised(Pleroma.Web.Streamer.supervisor()) + :ok + end + def start_socket(qs \\ nil, headers \\ []) do path = case qs do @@ -32,6 +37,7 @@ test "refuses invalid requests" do capture_log(fn -> assert {:error, {400, _}} = start_socket() assert {:error, {404, _}} = start_socket("?stream=ncjdk") + Process.sleep(30) end) end @@ -39,17 +45,16 @@ test "requires authentication and a valid token for protected streams" do capture_log(fn -> assert {:error, {403, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa") assert {:error, {403, _}} = start_socket("?stream=user") + Process.sleep(30) end) end - @tag needs_streamer: true test "allows public streams without authentication" do assert {:ok, _} = start_socket("?stream=public") assert {:ok, _} = start_socket("?stream=public:local") assert {:ok, _} = start_socket("?stream=hashtag&tag=lain") end - @tag needs_streamer: true test "receives well formatted events" do user = insert(:user) {:ok, _} = start_socket("?stream=public") @@ -94,31 +99,32 @@ test "accepts valid tokens", state do assert {:ok, _} = start_socket("?stream=user&access_token=#{state.token.token}") end - @tag needs_streamer: true test "accepts the 'user' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") assert capture_log(fn -> assert {:error, {403, "Forbidden"}} = start_socket("?stream=user") + Process.sleep(30) end) =~ ":badarg" end - @tag needs_streamer: true test "accepts the 'user:notification' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") assert capture_log(fn -> assert {:error, {403, "Forbidden"}} = start_socket("?stream=user:notification") + Process.sleep(30) end) =~ ":badarg" end - @tag needs_streamer: true test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}]) assert capture_log(fn -> assert {:error, {403, "Forbidden"}} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}]) + + Process.sleep(30) end) =~ ":badarg" end end From 6193157f1998b10ac6cb9f4d36dd863eced81b37 Mon Sep 17 00:00:00 2001 From: Steven Fuchs Date: Tue, 17 Sep 2019 18:12:27 +0000 Subject: [PATCH 098/272] Fix notification warnings --- lib/pleroma/workers/web_pusher_worker.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex index bea2baffb..61b451e3e 100644 --- a/lib/pleroma/workers/web_pusher_worker.ex +++ b/lib/pleroma/workers/web_pusher_worker.ex @@ -10,7 +10,11 @@ defmodule Pleroma.Workers.WebPusherWorker do @impl Oban.Worker def perform(%{"op" => "web_push", "notification_id" => notification_id}, _job) do - notification = Repo.get(Notification, notification_id) + notification = + Notification + |> Repo.get(notification_id) + |> Repo.preload([:activity]) + Pleroma.Web.Push.Impl.perform(notification) end end From 8d812c28a70ae174985000e98b9618dad746b22e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 17 Sep 2019 21:51:50 +0300 Subject: [PATCH 099/272] Update Tesla to 1.3 This version includes a couple of fixes, adds Gun and Mint adapters and removes 0.x -> 1.0 config migrator, which for some reason fails under certain conditions. I had to set `override: true` because Quack pins Tesla to `1.2.0`, but I have looked through the source code and verified that updating Tesla doesn't break anything there. --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index 230f90244..d8d3f802d 100644 --- a/mix.exs +++ b/mix.exs @@ -113,7 +113,7 @@ defp deps do {:calendar, "~> 0.17.4"}, {:cachex, "~> 3.0.2"}, {:poison, "~> 3.0", override: true}, - {:tesla, "~> 1.2"}, + {:tesla, "~> 1.3", override: true}, {:jason, "~> 1.0"}, {:mogrify, "~> 0.6.1"}, {:ex_aws, "~> 2.1"}, diff --git a/mix.lock b/mix.lock index 547ff6be6..24b34c09c 100644 --- a/mix.lock +++ b/mix.lock @@ -90,7 +90,7 @@ "swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]}, "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, - "tesla": {:hex, :tesla, "1.2.1", "864783cc27f71dd8c8969163704752476cec0f3a51eb3b06393b3971dc9733ff", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"}, + "tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "tzdata": {:hex, :tzdata, "0.5.21", "8cbf3607fcce69636c672d5be2bbb08687fe26639a62bdcc283d267277db7cf0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, From d201eec45cc5eb8c7b0c912c14be4704dbb4c1b1 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 17 Sep 2019 22:02:37 +0300 Subject: [PATCH 100/272] fixed ecto version --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 230f90244..58d1606d3 100644 --- a/mix.exs +++ b/mix.exs @@ -99,7 +99,7 @@ defp deps do {:plug_cowboy, "~> 2.0"}, {:phoenix_pubsub, "~> 1.1"}, {:phoenix_ecto, "~> 4.0"}, - {:ecto_sql, "~> 3.1"}, + {:ecto_sql, "~> 3.2"}, {:postgrex, ">= 0.13.5"}, {:oban, "~> 0.8.1"}, {:quantum, "~> 2.3"}, From 228bfd8a70cefadb8673ed6d11485944ef7c5666 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 17 Sep 2019 22:36:42 +0300 Subject: [PATCH 101/272] Bump elixir version to ~> 1.8 --- CHANGELOG.md | 1 + mix.exs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eb72c002..f2d149304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Remove `Reply-To` header from report emails for admins. ### Changed +- **Breaking:** Now pleroma requires Elixir ~> 1.8 (it was ~> 1.7) - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config - **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired - **Breaking:** `/api/pleroma/notifications/read` is moved to `/api/v1/pleroma/notifications/read` and now supports `max_id` and responds with Mastodon API entities. diff --git a/mix.exs b/mix.exs index 230f90244..7d262a60f 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ def project do [ app: :pleroma, version: version("1.0.0"), - elixir: "~> 1.7", + elixir: "~> 1.8", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix, :gettext] ++ Mix.compilers(), elixirc_options: [warnings_as_errors: true], From 35dcea3e13673b8a1a078a1f6fbc44f1e2098c22 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 13 Sep 2019 17:05:19 +0200 Subject: [PATCH 102/272] Remove [true,false] for booleans, it is implicit --- config/description.exs | 262 +++++++++++------------------------------ 1 file changed, 68 insertions(+), 194 deletions(-) diff --git a/config/description.exs b/config/description.exs index 32d36d6d6..5ae32d0f2 100644 --- a/config/description.exs +++ b/config/description.exs @@ -39,11 +39,7 @@ key: :link_name, type: :boolean, description: - "If enabled, a name parameter will be added to the url of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`", - suggestions: [ - true, - false - ] + "If enabled, a name parameter will be added to the url of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`" }, %{ key: :base_url, @@ -57,11 +53,7 @@ key: :proxy_remote, type: :boolean, description: - "If enabled, requests to media stored using a remote uploader will be proxied instead of being redirected.", - suggestions: [ - true, - false - ] + "If enabled, requests to media stored using a remote uploader will be proxied instead of being redirected." }, %{ key: :proxy_opts, @@ -190,11 +182,7 @@ %{ key: :enabled, type: :boolean, - description: "Allow/disallow send emails", - suggestions: [ - true, - false - ] + description: "Allow/disallow send emails" }, %{ group: {:subgroup, Swoosh.Adapters.SMTP}, @@ -221,8 +209,7 @@ group: {:subgroup, Swoosh.Adapters.SMTP}, key: :ssl, type: :boolean, - description: "`Swoosh.Adapters.SMTP` adapter specific setting", - suggestions: [true, false] + description: "`Swoosh.Adapters.SMTP` adapter specific setting" }, %{ group: {:subgroup, Swoosh.Adapters.SMTP}, @@ -256,8 +243,7 @@ group: {:subgroup, Swoosh.Adapters.SMTP}, key: :no_mx_lookups, type: :boolean, - description: "`Swoosh.Adapters.SMTP` adapter specific setting", - suggestions: [true, false] + description: "`Swoosh.Adapters.SMTP` adapter specific setting" }, %{ group: {:subgroup, Swoosh.Adapters.Sendgrid}, @@ -284,8 +270,7 @@ group: {:subgroup, Swoosh.Adapters.Sendmail}, key: :qmail, type: :boolean, - description: "`Swoosh.Adapters.Sendmail` adapter specific setting", - suggestions: [true, false] + description: "`Swoosh.Adapters.Sendmail` adapter specific setting" }, %{ group: {:subgroup, Swoosh.Adapters.Mandrill}, @@ -553,38 +538,22 @@ %{ key: :registrations_open, type: :boolean, - description: "Enable registrations for anyone, invitations can be enabled when false", - suggestions: [ - true, - false - ] + description: "Enable registrations for anyone, invitations can be enabled when false" }, %{ key: :invites_enabled, type: :boolean, - description: "Enable user invitations for admins (depends on registrations_open: false)", - suggestions: [ - true, - false - ] + description: "Enable user invitations for admins (depends on registrations_open: false)" }, %{ key: :account_activation_required, type: :boolean, - description: "Require users to confirm their emails before signing in", - suggestions: [ - true, - false - ] + description: "Require users to confirm their emails before signing in" }, %{ key: :federating, type: :boolean, - description: "Enable federation with other instances", - suggestions: [ - true, - false - ] + description: "Enable federation with other instances" }, %{ key: :federation_incoming_replies_max_depth, @@ -618,11 +587,7 @@ %{ key: :allow_relay, type: :boolean, - description: "Enable Pleroma's Relay, which makes it possible to follow a whole instance", - suggestions: [ - true, - false - ] + description: "Enable Pleroma's Relay, which makes it possible to follow a whole instance" }, %{ key: :rewrite_policy, @@ -638,11 +603,7 @@ type: :boolean, description: "Makes the client API in authentificated mode-only except for user-profiles." <> - " Useful for disabling the Local Timeline and The Whole Known Network", - suggestions: [ - true, - false - ] + " Useful for disabling the Local Timeline and The Whole Known Network" }, %{ key: :quarantined_instances, @@ -658,11 +619,7 @@ key: :managed_config, type: :boolean, description: - "Whenether the config for pleroma-fe is configured in this config or in static/config.json", - suggestions: [ - true, - false - ] + "Whenether the config for pleroma-fe is configured in this config or in static/config.json" }, %{ key: :static_dir, @@ -689,11 +646,7 @@ key: :mrf_transparency, type: :boolean, description: - "Make the content of your Message Rewrite Facility settings public (via nodeinfo)", - suggestions: [ - true, - false - ] + "Make the content of your Message Rewrite Facility settings public (via nodeinfo)" }, %{ key: :mrf_transparency_exclusions, @@ -709,11 +662,7 @@ type: :boolean, description: "Set to true to use extended local nicknames format (allows underscores/dashes)." <> - " This will break federation with older software for theses nicknames", - suggestions: [ - true, - false - ] + " This will break federation with older software for theses nicknames" }, %{ key: :max_pinned_statuses, @@ -741,11 +690,7 @@ key: :no_attachment_links, type: :boolean, description: - "Set to true to disable automatically adding attachment link text to statuses", - suggestions: [ - true, - false - ] + "Set to true to disable automatically adding attachment link text to statuses" }, %{ key: :welcome_message, @@ -780,20 +725,12 @@ description: "If set to true, only mentions at the beginning of a post will be used to address people in direct messages." <> " This is to prevent accidental mentioning of people when talking about them (e.g. \"@friend hey i really don't like @enemy\")." <> - " Default: false", - suggestions: [ - true, - false - ] + " Default: false" }, %{ key: :healthcheck, type: :boolean, - description: "If set to true, system data will be shown on /api/pleroma/healthcheck", - suggestions: [ - true, - false - ] + description: "If set to true, system data will be shown on /api/pleroma/healthcheck" }, %{ key: :remote_post_retention_days, @@ -823,11 +760,7 @@ %{ key: :skip_thread_containment, type: :boolean, - description: "Skip filter out broken threads. The default is true", - suggestions: [ - true, - false - ] + description: "Skip filter out broken threads. The default is true" }, %{ key: :limit_to_local_content, @@ -844,11 +777,7 @@ key: :dynamic_configuration, type: :boolean, description: - "Allow transferring configuration to DB with the subsequent customization from Admin api. Defaults to `false`", - suggestions: [ - true, - false - ] + "Allow transferring configuration to DB with the subsequent customization from Admin api. Defaults to `false`" }, %{ key: :max_account_fields, @@ -886,11 +815,7 @@ %{ key: :external_user_synchronization, type: :boolean, - description: "Enabling following/followers counters synchronization for external users", - suggestions: [ - true, - false - ] + description: "Enabling following/followers counters synchronization for external users" } ] }, @@ -1069,48 +994,40 @@ %{ key: :showInstanceSpecificPanel, type: :boolean, - description: "Whenether to show the instance's specific panel", - suggestions: [true, false] + description: "Whenether to show the instance's specific panel" }, %{ key: :scopeOptionsEnabled, type: :boolean, - description: "Enable setting an notice visibility and subject/CW when posting", - suggestions: [true, false] + description: "Enable setting an notice visibility and subject/CW when posting" }, %{ key: :formattingOptionsEnabled, type: :boolean, description: - "Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to :instance, allowed_post_formats", - suggestions: [true, false] + "Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to :instance, allowed_post_formats" }, %{ key: :collapseMessageWithSubject, type: :boolean, description: - "When a message has a subject(aka Content Warning), collapse it by default", - suggestions: [true, false] + "When a message has a subject(aka Content Warning), collapse it by default" }, %{ key: :hidePostStats, type: :boolean, - description: "Hide notices statistics(repeats, favorites, ...)", - suggestions: [true, false] + description: "Hide notices statistics(repeats, favorites, ...)" }, %{ key: :hideUserStats, type: :boolean, description: - "Hide profile statistics(posts, posts per day, followers, followings, ...)", - suggestions: [true, false] + "Hide profile statistics(posts, posts per day, followers, followings, ...)" }, %{ key: :scopeCopy, type: :boolean, - description: - "Copy the scope (private/unlisted/public) in replies to posts by default", - suggestions: [true, false] + description: "Copy the scope (private/unlisted/public) in replies to posts by default" }, %{ key: :subjectLineBehavior, @@ -1124,8 +1041,7 @@ %{ key: :alwaysShowSubjectInput, type: :boolean, - description: "When set to false, auto-hide the subject field when it's empty", - suggestions: [true, false] + description: "When set to false, auto-hide the subject field when it's empty" } ] }, @@ -1142,8 +1058,7 @@ %{ key: :showInstanceSpecificPanel, type: :boolean, - description: "Whenether to show the instance's specific panel", - suggestions: [true, false] + description: "Whenether to show the instance's specific panel" } ] } @@ -1271,14 +1186,12 @@ %{ key: :allow_followersonly, type: :boolean, - description: "whether to allow followers-only posts", - suggestions: [true, false] + description: "whether to allow followers-only posts" }, %{ key: :allow_direct, type: :boolean, - description: "whether to allow direct messages", - suggestions: [true, false] + description: "whether to allow direct messages" } ] }, @@ -1393,8 +1306,7 @@ %{ key: :enabled, type: :boolean, - description: "Enables proxying of remote media to the instance's proxy", - suggestions: [true, false] + description: "Enables proxying of remote media to the instance's proxy" }, %{ key: :base_url, @@ -1426,8 +1338,7 @@ %{ key: :enabled, type: :boolean, - description: "Enables the gopher interface", - suggestions: [true, false] + description: "Enables the gopher interface" }, %{ key: :ip, @@ -1601,8 +1512,7 @@ %{ key: :secure_cookie_flag, type: :boolean, - description: "", - suggestions: [true, false] + description: "" }, %{ key: :extra_cookie_attrs, @@ -1621,20 +1531,17 @@ %{ key: :unfollow_blocked, type: :boolean, - description: "Whether blocks result in people getting unfollowed", - suggestions: [true, false] + description: "Whether blocks result in people getting unfollowed" }, %{ key: :outgoing_blocks, type: :boolean, - description: "Whether to federate blocks to other instances", - suggestions: [true, false] + description: "Whether to federate blocks to other instances" }, %{ key: :sign_object_fetches, type: :boolean, - description: "Sign object fetches with HTTP signatures", - suggestions: [true, false] + description: "Sign object fetches with HTTP signatures" }, %{ key: :follow_handshake_timeout, @@ -1653,14 +1560,12 @@ %{ key: :enabled, type: :boolean, - description: "Whether the managed content security policy is enabled", - suggestions: [true, false] + description: "Whether the managed content security policy is enabled" }, %{ key: :sts, type: :boolean, - description: "Whether to additionally send a Strict-Transport-Security header", - suggestions: [true, false] + description: "Whether to additionally send a Strict-Transport-Security header" }, %{ key: :sts_max_age, @@ -1727,8 +1632,7 @@ %{ key: :enabled, type: :boolean, - description: "Whether the captcha should be shown on registration", - suggestions: [true, false] + description: "Whether the captcha should be shown on registration" }, %{ key: :method, @@ -1817,8 +1721,7 @@ %{ key: :verbose, type: :boolean, - description: "Logs verbose mode", - suggestions: [false, true] + description: "Logs verbose mode" }, %{ key: :prune, @@ -1937,11 +1840,7 @@ %{ key: :unfurl_nsfw, type: :boolean, - description: "If set to true nsfw attachments will be shown in previews", - suggestions: [ - true, - false - ] + description: "If set to true nsfw attachments will be shown in previews" } ] }, @@ -1955,8 +1854,7 @@ key: :enabled, type: :boolean, description: - "if enabled the instance will parse metadata from attached links to generate link previews", - suggestions: [true, false] + "if enabled the instance will parse metadata from attached links to generate link previews" }, %{ key: :ignore_hosts, @@ -1998,8 +1896,7 @@ key: :enabled, type: :boolean, description: - "if enabled, when a new user is federated with, fetch some of their latest posts", - suggestions: [true, false] + "if enabled, when a new user is federated with, fetch some of their latest posts" }, %{ key: :pages, @@ -2030,14 +1927,12 @@ %{ key: :new_window, type: :boolean, - description: "set to false to remove target='_blank' attribute", - suggestions: [true, false] + description: "set to false to remove target='_blank' attribute" }, %{ key: :scheme, type: :boolean, - description: "Set to true to link urls with schema http://google.com", - suggestions: [true, false] + description: "Set to true to link urls with schema http://google.com" }, %{ key: :truncate, @@ -2049,14 +1944,12 @@ %{ key: :strip_prefix, type: :boolean, - description: "Strip the scheme prefix", - suggestions: [true, false] + description: "Strip the scheme prefix" }, %{ key: :extra, type: :boolean, - description: "link urls with rarely used schemes (magnet, ipfs, irc, etc.)", - suggestions: [true, false] + description: "link urls with rarely used schemes (magnet, ipfs, irc, etc.)" } ] }, @@ -2083,8 +1976,7 @@ %{ key: :enabled, type: :boolean, - description: "whether scheduled activities are sent to the job queue to be executed", - suggestions: [true, false] + description: "whether scheduled activities are sent to the job queue to be executed" } ] }, @@ -2097,8 +1989,7 @@ %{ key: :enabled, type: :boolean, - description: "whether expired activities will be sent to the job queue to be deleted", - suggestions: [true, false] + description: "whether expired activities will be sent to the job queue to be deleted" } ] }, @@ -2128,8 +2019,7 @@ %{ key: :enabled, type: :boolean, - description: "enables LDAP authentication", - suggestions: [true, false] + description: "enables LDAP authentication" }, %{ key: :host, @@ -2146,8 +2036,7 @@ %{ key: :ssl, type: :boolean, - description: "true to use SSL, usually implies the port 636", - suggestions: [true, false] + description: "true to use SSL, usually implies the port 636" }, %{ key: :sslopts, @@ -2158,8 +2047,7 @@ %{ key: :tls, type: :boolean, - description: "true to start TLS, usually implies the port 389", - suggestions: [true, false] + description: "true to start TLS, usually implies the port 389" }, %{ key: :tlsopts, @@ -2237,8 +2125,7 @@ %{ key: :active, type: :boolean, - description: "globally enable or disable digest emails", - suggestions: [true, false] + description: "globally enable or disable digest emails" }, %{ key: :schedule, @@ -2346,14 +2233,12 @@ key: :issue_new_refresh_token, type: :boolean, description: - "Keeps old refresh token or generate new refresh token when to obtain an access token", - suggestions: [true, false] + "Keeps old refresh token or generate new refresh token when to obtain an access token" }, %{ key: :clean_expired_tokens, type: :boolean, - description: "Enable a background job to clean expired oauth tokens. Defaults to false", - suggestions: [true, false] + description: "Enable a background job to clean expired oauth tokens. Defaults to false" }, %{ key: :clean_expired_tokens_interval, @@ -2415,8 +2300,7 @@ %{ key: :rum_enabled, type: :boolean, - description: "If RUM indexes should be used. Defaults to false", - suggestions: [true, false] + description: "If RUM indexes should be used. Defaults to false" } ] }, @@ -2475,8 +2359,7 @@ %{ key: :enabled, type: :boolean, - description: "Enables ssh", - suggestions: [true, false] + description: "Enables ssh" }, %{ key: :priv_dir, @@ -2579,8 +2462,7 @@ %{ key: :enabled, type: :boolean, - description: "", - suggestions: [true, false] + description: "" } ] }, @@ -2593,8 +2475,7 @@ %{ key: :enabled, type: :boolean, - description: "Enables suggestions", - suggestions: [] + description: "Enables suggestions" }, %{ key: :third_party_engine, @@ -2686,8 +2567,7 @@ %{ key: :send_user_agent, type: :boolean, - description: "", - suggestions: [true, false] + description: "" }, %{ key: :adapter, @@ -2715,26 +2595,22 @@ %{ key: :allow_inline_images, type: :boolean, - description: "", - suggestions: [true, false] + description: "" }, %{ key: :allow_headings, type: :boolean, - description: "", - suggestions: [true, false] + description: "" }, %{ key: :allow_tables, type: :boolean, - description: "", - suggestions: [true, false] + description: "" }, %{ key: :allow_fonts, type: :boolean, - description: "", - suggestions: [true, false] + description: "" }, %{ key: :scrub_policy, @@ -2753,8 +2629,7 @@ %{ key: :deny_follow_blocked, type: :boolean, - description: "", - suggestions: [true, false] + description: "" } ] }, @@ -2854,8 +2729,7 @@ %{ key: :credentials, type: :boolean, - description: "", - suggestions: [true, false] + description: "" }, %{ key: :headers, From 7f211a48e0c443cbff90f028c5c92c496f66c62e Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 21:43:27 +0200 Subject: [PATCH 103/272] docs/markdown.ex: child header as "- key (type): description" --- lib/pleroma/docs/markdown.ex | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index 8386dc2fb..58a42b323 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -44,6 +44,13 @@ def process(descriptions) do {:ok, config_path} end + defp print_child_header(file, child) do + IO.write( + file, + "- `#{inspect(child[:key])}` (`#{inspect(child[:type])}`): #{child[:description]}\n" + ) + end + defp print_suggestion(file, suggestion) when is_list(suggestion) do IO.write(file, " `#{inspect(suggestion)}`\n") end @@ -70,9 +77,4 @@ defp print_suggestions(file, suggestions) do print_suggestion(file, List.first(suggestions)) end end - - defp print_child_header(file, child) do - IO.write(file, "- `#{inspect(child[:key])}` -`#{inspect(child[:type])}` \n") - IO.write(file, "#{child[:description]} \n") - end end From e686f9be818ebddfba1aedcd9ae328d26147dca8 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 17 Sep 2019 20:04:57 +0000 Subject: [PATCH 104/272] Apply suggestion to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2d149304..58618b7f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Remove `Reply-To` header from report emails for admins. ### Changed -- **Breaking:** Now pleroma requires Elixir ~> 1.8 (it was ~> 1.7) +- **Breaking:** Elixir >=1.8 is now required (was >= 1.7) - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config - **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired - **Breaking:** `/api/pleroma/notifications/read` is moved to `/api/v1/pleroma/notifications/read` and now supports `max_id` and responds with Mastodon API entities. From f9dd121ad3f7e1de465f81c7a5fe4e4173d88e28 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 17 Sep 2019 23:09:08 +0300 Subject: [PATCH 105/272] Admin API: Return link alongside with token on password reset --- CHANGELOG.md | 1 + lib/pleroma/web/admin_api/admin_api_controller.ex | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eb72c002..0f4a171c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). – Pagination: (optional) return `total` alongside with `items` when paginating - Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler +- Admin API: Return link alongside with token on password reset ### Fixed - Following from Osada diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 544b9d7d8..03a73053b 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -432,9 +432,14 @@ def revoke_invite(conn, %{"token" => token}) do def get_password_reset(conn, %{"nickname" => nickname}) do (%User{local: true} = user) = User.get_cached_by_nickname(nickname) {:ok, token} = Pleroma.PasswordResetToken.create_token(user) + host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host]) + protocol = Pleroma.Config.get([Pleroma.Web.Endpoint, :protocol]) conn - |> json(token.token) + |> json(%{ + token: token.token, + link: "#{protocol}://#{host}/api/pleroma/password_reset/#{token}" + }) end def list_reports(conn, params) do From bf8567996c6149e5a7857ccf74697184adb42be9 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 17 Sep 2019 23:48:26 +0300 Subject: [PATCH 106/272] Sync develop changelog with master and create a new section for post-1.1 changes --- CHANGELOG.md | 92 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4426e3f70..1f0d55e9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,24 +4,25 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Changed +- **Breaking:** Elixir >=1.8 is now required (was >= 1.7) +- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) +- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler +- Admin API: Return `total` when querying for reports + +## [1.1.0] - 2019-??-?? ### Security -- OStatus: eliminate the possibility of a protocol downgrade attack. -- OStatus: prevent following locked accounts, bypassing the approval process. - Mastodon API: respect post privacy in `/api/v1/statuses/:id/{favourited,reblogged}_by` ### Removed - **Breaking:** GNU Social API with Qvitter extensions support -- **Breaking:** ActivityPub: The `accept_blocks` configuration setting. - Emoji: Remove longfox emojis. - Remove `Reply-To` header from report emails for admins. ### Changed -- **Breaking:** Elixir >=1.8 is now required (was >= 1.7) - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config - **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired - **Breaking:** `/api/pleroma/notifications/read` is moved to `/api/v1/pleroma/notifications/read` and now supports `max_id` and responds with Mastodon API entities. -- Configuration: OpenGraph and TwitterCard providers enabled by default -- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text - Configuration: added `config/description.exs`, from which `docs/config.md` is generated - Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set - NodeInfo: Return `skipThreadContainment` in `metadata` for the `skip_thread_containment` option @@ -31,24 +32,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) - Improve digest email template – Pagination: (optional) return `total` alongside with `items` when paginating -- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) -- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler -- Admin API: Return `total` when querying for reports ### Fixed - Following from Osada -- Not being able to pin unlisted posts -- Objects being re-embedded to activities after being updated (e.g faved/reposted). Running 'mix pleroma.database prune_objects' again is advised. - Favorites timeline doing database-intensive queries - Metadata rendering errors resulting in the entire page being inaccessible - `federation_incoming_replies_max_depth` option being ignored in certain cases -- Federation/MediaProxy not working with instances that have wrong certificate order - Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`) - Mastodon API: Misskey's endless polls being unable to render - Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity - Mastodon API: Notifications endpoint crashing if one notification failed to render -- Mastodon API: follower/following counters not being nullified, when `hide_follows`/`hide_followers` is set -- Mastodon API: `muted` in the Status entity, using author's account to determine if the tread was muted - Mastodon API: Add `account_id`, `type`, `offset`, and `limit` to search API (`/api/v1/search` and `/api/v2/search`) - Mastodon API, streaming: Fix filtering of notifications based on blocks/mutes/thread mutes - ActivityPub C2S: follower/following collection pages being inaccessible even when authentifucated if `hide_followers`/ `hide_follows` was set @@ -56,15 +49,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Rich Media: Parser failing when no TTL can be found by image TTL setters - Rich Media: The crawled URL is now spliced into the rich media data. - ActivityPub S2S: sharedInbox usage has been mostly aligned with the rules in the AP specification. -- ActivityPub S2S: remote user deletions now work the same as local user deletions. -- ActivityPub S2S: POST requests are now signed with `(request-target)` pseudo-header. -- Not being able to access the Mastodon FE login page on private instances -- Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag - Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected. - Report email not being sent to admins when the reporter is a remote user -- MRF: ensure that subdomain_match calls are case-insensitive - Reverse Proxy limiting `max_body_length` was incorrectly defined and only checked `Content-Length` headers which may not be sufficient in some circumstances -- MRF: fix use of unserializable keyword lists in describe() implementations - ActivityPub: Deactivated user deletion - ActivityPub: Fix `/users/:nickname/inbox` crashing without an authenticated user - MRF: fix ability to follow a relay when AntiFollowbotPolicy was enabled @@ -75,16 +62,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: all status JSON responses contain a `pleroma.expires_at` item which states when an activity will expire. The value is only shown to the user who created the activity. To everyone else it's empty. - Configuration: `ActivityExpiration.enabled` controls whether expired activites will get deleted at the appropriate time. Enabled by default. - Conversations: Add Pleroma-specific conversation endpoints and status posting extensions. Run the `bump_all_conversations` task again to create the necessary data. -- **Breaking:** MRF describe API, which adds support for exposing configuration information about MRF policies to NodeInfo. - Custom modules will need to be updated by adding, at the very least, `def describe, do: {:ok, %{}}` to the MRF policy modules. - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) - MRF: Support for excluding specific domains from Transparency. - MRF: Support for filtering posts based on who they mention (`Pleroma.Web.ActivityPub.MRF.MentionPolicy`) -- MRF: Support for filtering posts based on ActivityStreams vocabulary (`Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`) -- MRF (Simple Policy): Support for wildcard domains. -- Support for wildcard domains in user domain blocks setting. -- Configuration: `quarantined_instances` support wildcard domains. -- Configuration: `federation_incoming_replies_max_depth` option - Mastodon API: Support for the [`tagged` filter](https://github.com/tootsuite/mastodon/pull/9755) in [`GET /api/v1/accounts/:id/statuses`](https://docs.joinmastodon.org/api/rest/accounts/#get-api-v1-accounts-id-statuses) - Mastodon API, streaming: Add support for passing the token in the `Sec-WebSocket-Protocol` header - Mastodon API, extension: Ability to reset avatar, profile banner, and background @@ -112,9 +92,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Admin API: Endpoint for fetching latest user's statuses - Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=` for resending account confirmation. - Pleroma API: Email change endpoint. -- Relays: Added a task to list relay subscriptions. -- Mix Tasks: `mix pleroma.database fix_likes_collections` -- Federation: Remove `likes` from objects. - Admin API: Added moderation log - Web response cache (currently, enabled for ActivityPub) - Mastodon API: Added an endpoint to get multiple statuses by IDs (`GET /api/v1/statuses/?ids[]=1&ids[]=2`) @@ -125,6 +102,61 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - RichMedia: parsers and their order are configured in `rich_media` config. - RichMedia: add the rich media ttl based on image expiration time. +## [1.0.6] - 2019-08-14 +### Fixed +- MRF: fix use of unserializable keyword lists in describe() implementations +- ActivityPub S2S: POST requests are now signed with `(request-target)` pseudo-header. + +## [1.0.5] - 2019-08-13 +### Fixed +- Mastodon API: follower/following counters not being nullified, when `hide_follows`/`hide_followers` is set +- Mastodon API: `muted` in the Status entity, using author's account to determine if the thread was muted +- Mastodon API: return the actual profile URL in the Account entity's `url` property when appropriate +- Templates: properly style anchor tags +- Objects being re-embedded to activities after being updated (e.g faved/reposted). Running 'mix pleroma.database prune_objects' again is advised. +- Not being able to access the Mastodon FE login page on private instances +- MRF: ensure that subdomain_match calls are case-insensitive +- Fix internal server error when using the healthcheck API. + +### Added +- **Breaking:** MRF describe API, which adds support for exposing configuration information about MRF policies to NodeInfo. + Custom modules will need to be updated by adding, at the very least, `def describe, do: {:ok, %{}}` to the MRF policy modules. +- Relays: Added a task to list relay subscriptions. +- MRF: Support for filtering posts based on ActivityStreams vocabulary (`Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`) +- MRF (Simple Policy): Support for wildcard domains. +- Support for wildcard domains in user domain blocks setting. +- Configuration: `quarantined_instances` support wildcard domains. +- Mix Tasks: `mix pleroma.database fix_likes_collections` +- Configuration: `federation_incoming_replies_max_depth` option + +### Removed +- Federation: Remove `likes` from objects. +- ActivityPub: The `accept_blocks` configuration setting. + +## [1.0.4] - 2019-08-01 +### Fixed +- Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag + +## [1.0.3] - 2019-07-31 +### Security +- OStatus: eliminate the possibility of a protocol downgrade attack. +- OStatus: prevent following locked accounts, bypassing the approval process. +- TwitterAPI: use CommonAPI to handle remote follows instead of OStatus. + +## [1.0.2] - 2019-07-28 +### Fixed +- Not being able to pin unlisted posts +- Mastodon API: represent poll IDs as strings +- MediaProxy: fix matching filenames +- MediaProxy: fix filename encoding +- Migrations: fix a sporadic migration failure +- Metadata rendering errors resulting in the entire page being inaccessible +- Federation/MediaProxy not working with instances that have wrong certificate order +- ActivityPub S2S: remote user deletions now work the same as local user deletions. + +### Changed +- Configuration: OpenGraph and TwitterCard providers enabled by default +- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text ## [1.0.1] - 2019-07-14 ### Security From 50ec445b2c1e45b0d3b3a2016650f3262ed00e75 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 21:57:13 +0200 Subject: [PATCH 107/272] description.exs: remove empty strings and arrays --- config/description.exs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/config/description.exs b/config/description.exs index 5ae32d0f2..959d839bc 100644 --- a/config/description.exs +++ b/config/description.exs @@ -109,8 +109,7 @@ type: :string, description: "If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or \"\" etc." <> - " For example, when using CDN to S3 virtual host format, set \"\". At this time, write CNAME to CDN in public_endpoint.", - suggestions: [""] + " For example, when using CDN to S3 virtual host format, set \"\". At this time, write CNAME to CDN in public_endpoint." } ] }, @@ -360,22 +359,19 @@ group: {:subgroup, Swoosh.Adapters.SocketLabs}, key: :server_id, type: :string, - description: "`Swoosh.Adapters.SocketLabs` adapter specific setting", - suggestions: [""] + description: "`Swoosh.Adapters.SocketLabs` adapter specific setting" }, %{ group: {:subgroup, Swoosh.Adapters.SocketLabs}, key: :api_key, type: :string, - description: "`Swoosh.Adapters.SocketLabs` adapter specific setting", - suggestions: [""] + description: "`Swoosh.Adapters.SocketLabs` adapter specific setting" }, %{ group: {:subgroup, Swoosh.Adapters.Gmail}, key: :access_token, type: :string, - description: "`Swoosh.Adapters.Gmail` adapter specific setting", - suggestions: [""] + description: "`Swoosh.Adapters.Gmail` adapter specific setting" } ] }, @@ -1682,8 +1678,7 @@ group: :pleroma_job_queue, key: :queues, type: :group, - description: "[Deprecated] Replaced with `Oban`/`:queues` (keeping the same format)", - children: [] + description: "[Deprecated] Replaced with `Oban`/`:queues` (keeping the same format)" }, %{ group: :pleroma, @@ -1694,8 +1689,7 @@ %{ key: :max_retries, type: :integer, - description: "[Deprecated] Replaced as `Oban`/`:queues`/`:outgoing_federation` value", - suggestions: [] + description: "[Deprecated] Replaced as `Oban`/`:queues`/`:outgoing_federation` value" } ] }, @@ -2041,8 +2035,7 @@ %{ key: :sslopts, type: :keyword, - description: "additional SSL options", - suggestions: [] + description: "additional SSL options" }, %{ key: :tls, @@ -2052,8 +2045,7 @@ %{ key: :tlsopts, type: :keyword, - description: "additional TLS options", - suggestions: [] + description: "additional TLS options" }, %{ key: :base, From e0d8c8897e46d20039b4c0a383bca0192c5eb2ec Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 22:00:02 +0200 Subject: [PATCH 108/272] docs/markdown.ex: do no print empty suggestions --- lib/pleroma/docs/markdown.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index 58a42b323..d7ca97957 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -66,6 +66,8 @@ defp print_suggestion(file, suggestion, as_list \\ false) do defp print_suggestions(_file, nil), do: nil + defp print_suggestions(_file, ""), do: nil + defp print_suggestions(file, suggestions) do IO.write(file, "Suggestions:\n") From 106afaed58da3a25d1c4593e13192ad2145643e4 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 22:04:21 +0200 Subject: [PATCH 109/272] markdown.ex: do not fail if there is no children --- lib/pleroma/docs/markdown.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index d7ca97957..20bd1c896 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -23,7 +23,7 @@ def process(descriptions) do IO.write(file, "#{group[:description]}\n") - for child <- group[:children] do + for child <- group[:children] || [] do print_child_header(file, child) print_suggestions(file, child[:suggestions]) From c0c56282007aff88a923bba4769af894cb6235af Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 22:14:56 +0200 Subject: [PATCH 110/272] description.exs: remove empty strings on descriptions --- config/description.exs | 76 +++++------------------------------- lib/pleroma/docs/markdown.ex | 8 +++- 2 files changed, 15 insertions(+), 69 deletions(-) diff --git a/config/description.exs b/config/description.exs index 959d839bc..821b76972 100644 --- a/config/description.exs +++ b/config/description.exs @@ -857,7 +857,6 @@ %{ key: :metadata, type: {:list, :atom}, - description: "", suggestions: [[:request_id]] } ] @@ -883,7 +882,6 @@ %{ key: :metadata, type: {:list, :atom}, - description: "", suggestions: [[:request_id]] } ] @@ -1177,7 +1175,6 @@ group: :pleroma, key: :mrf_rejectnonpublic, type: :group, - description: "", children: [ %{ key: :allow_followersonly, @@ -1444,43 +1441,36 @@ %{ key: :instrumenters, type: {:list, :module}, - description: "", suggestions: [Pleroma.Web.Endpoint.Instrumenter] }, %{ key: :protocol, type: :string, - description: "", suggestions: ["https"] }, %{ key: :secret_key_base, type: :string, - description: "", suggestions: ["aK4Abxf29xU9TTDKre9coZPUgevcVCFQJe/5xP/7Lt4BEif6idBIbjupVbOrbKxl"] }, %{ key: :signing_salt, type: :string, - description: "", suggestions: ["CqaoopA2"] }, %{ key: :render_errors, type: :keyword, - description: "", suggestions: [[view: Pleroma.Web.ErrorView, accepts: ~w(json)]], children: [ %{ key: :view, type: :module, - description: "", suggestions: [Pleroma.Web.ErrorView] }, %{ key: :accepts, type: {:list, :string}, - description: "", suggestions: ["json"] } ] @@ -1488,32 +1478,27 @@ %{ key: :pubsub, type: :keyword, - description: "", suggestions: [[name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2]], children: [ %{ key: :name, type: :module, - description: "", suggestions: [Pleroma.PubSub] }, %{ key: :adapter, type: :module, - description: "", suggestions: [Phoenix.PubSub.PG2] } ] }, %{ key: :secure_cookie_flag, - type: :boolean, - description: "" + type: :boolean }, %{ key: :extra_cookie_attrs, type: {:list, :string}, - description: "", suggestions: ["SameSite=Lax"] } ] @@ -1842,7 +1827,6 @@ group: :pleroma, key: :rich_media, type: :group, - description: "", children: [ %{ key: :enabled, @@ -1995,7 +1979,6 @@ %{ key: Pleroma.Web.Auth.Authenticator, type: :module, - description: "", suggestions: [Pleroma.Web.Auth.PleromaAuthenticator, Pleroma.Web.Auth.LDAPAuthenticator] } ] @@ -2172,37 +2155,31 @@ %{ key: :link_color, type: :string, - description: "", suggestions: ["#d8a070"] }, %{ key: :background_color, type: :string, - description: "", suggestions: ["#2C3645"] }, %{ key: :content_background_color, type: :string, - description: "", suggestions: ["#1B2635"] }, %{ key: :header_color, type: :string, - description: "", suggestions: ["#d8a070"] }, %{ key: :text_color, type: :string, - description: "", suggestions: ["#b9b9ba"] }, %{ key: :text_muted_color, type: :string, - description: "", suggestions: ["#b9b9ba"] } ] @@ -2245,7 +2222,6 @@ group: :pleroma, key: :emoji, type: :group, - description: "", children: [ %{ key: :shortcode_globs, @@ -2387,7 +2363,6 @@ %{ key: :types, type: :map, - description: "", suggestions: [ %{ "application/xml" => ["xml"], @@ -2401,31 +2376,26 @@ %{ key: "application/xml", type: {:list, :string}, - description: "", suggestions: [["xml"]] }, %{ key: "application/xrd+xml", type: {:list, :string}, - description: "", suggestions: [["xrd+xml"]] }, %{ key: "application/jrd+json", type: {:list, :string}, - description: "", suggestions: [["jrd+json"]] }, %{ key: "application/activity+json", type: {:list, :string}, - description: "", suggestions: [["activity+json"]] }, %{ key: "application/ld+json", type: {:list, :string}, - description: "", suggestions: [["activity+json"]] } ] @@ -2453,8 +2423,7 @@ children: [ %{ key: :enabled, - type: :boolean, - description: "" + type: :boolean } ] }, @@ -2462,7 +2431,6 @@ group: :pleroma, key: :suggestions, type: :group, - description: "", children: [ %{ key: :enabled, @@ -2492,7 +2460,6 @@ %{ key: :web, type: :string, - description: "", suggestions: ["https://vinayaka.distsn.org"] } ] @@ -2519,7 +2486,6 @@ %{ key: :adapter, type: :module, - description: "", suggestions: [Pleroma.Signature] } ] @@ -2528,18 +2494,15 @@ group: :pleroma, key: Pleroma.Uploaders.MDII, type: :group, - description: "", children: [ %{ key: :cgi, type: :string, - description: "", suggestions: ["https://mdii.sakura.ne.jp/mdii-post.cgi"] }, %{ key: :files, type: :string, - description: "", suggestions: ["https://mdii.sakura.ne.jp"] } ] @@ -2553,18 +2516,15 @@ %{ key: :proxy_url, type: [:string, :atom, nil], - description: "", suggestions: ["localhost:9020", {:socks5, :localhost, 3090}, nil] }, %{ key: :send_user_agent, - type: :boolean, - description: "" + type: :boolean }, %{ key: :adapter, type: :keyword, - description: "", suggestions: [ [ ssl_options: [ @@ -2582,32 +2542,26 @@ group: :pleroma, key: :markup, type: :group, - description: "", children: [ %{ key: :allow_inline_images, - type: :boolean, - description: "" + type: :boolean }, %{ key: :allow_headings, - type: :boolean, - description: "" + type: :boolean }, %{ key: :allow_tables, - type: :boolean, - description: "" + type: :boolean }, %{ key: :allow_fonts, - type: :boolean, - description: "" + type: :boolean }, %{ key: :scrub_policy, type: {:list, :module}, - description: "", suggestions: [[Pleroma.HTML.Transform.MediaProxy, Pleroma.HTML.Scrubber.Default]] } ] @@ -2616,12 +2570,10 @@ group: :pleroma, key: :user, type: :group, - description: "", children: [ %{ key: :deny_follow_blocked, - type: :boolean, - description: "" + type: :boolean } ] }, @@ -2629,12 +2581,10 @@ group: :pleroma, key: :mrf_normalize_markup, type: :group, - description: "", children: [ %{ key: :scrub_policy, type: :module, - description: "", suggestions: [Pleroma.HTML.Scrubber.Default] } ] @@ -2643,12 +2593,10 @@ group: :pleroma, key: Pleroma.User, type: :group, - description: "", children: [ %{ key: :restricted_nicknames, type: {:list, :string}, - description: "", suggestions: [ [ ".well-known", @@ -2689,24 +2637,20 @@ %{ group: :cors_plug, type: :group, - description: "", children: [ %{ key: :max_age, type: :integer, - description: "", suggestions: [86_400] }, %{ key: :methods, type: {:list, :string}, - description: "", suggestions: [["POST", "PUT", "DELETE", "GET", "PATCH", "OPTIONS"]] }, %{ key: :expose, type: :string, - description: "", suggestions: [ [ "Link", @@ -2720,13 +2664,11 @@ }, %{ key: :credentials, - type: :boolean, - description: "" + type: :boolean }, %{ key: :headers, type: {:list, :string}, - description: "", suggestions: [["Authorization", "Content-Type", "Idempotency-Key"]] } ] diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index 20bd1c896..739e4fce3 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -44,13 +44,17 @@ def process(descriptions) do {:ok, config_path} end - defp print_child_header(file, child) do + defp print_child_header(file, %{key: key, type: type, description: description} = _child) do IO.write( file, - "- `#{inspect(child[:key])}` (`#{inspect(child[:type])}`): #{child[:description]}\n" + "- `#{inspect(key)}` (`#{inspect(type)}`): #{description}\n" ) end + defp print_child_header(file, %{key: key, type: type} = _child) do + IO.write(file, "- `#{inspect(key)}` (`#{inspect(type)}`)\n") + end + defp print_suggestion(file, suggestion) when is_list(suggestion) do IO.write(file, " `#{inspect(suggestion)}`\n") end From 32d64102cb2f8cf3b0f825f2ac0770563cfb457f Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 22:19:30 +0200 Subject: [PATCH 111/272] description.exs: uncomment type for email logo --- config/description.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/description.exs b/config/description.exs index 821b76972..65ea6bf01 100644 --- a/config/description.exs +++ b/config/description.exs @@ -2133,7 +2133,7 @@ children: [ %{ key: :logo, - # type: [:string, nil], + type: [:string, nil], description: "a path to a custom logo. Set it to nil to use the default Pleroma logo", suggestions: ["some/path/logo.png", nil] }, From d6182a3c8fef6377c20bb827a8e86bdac5bfb125 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 22:22:54 +0200 Subject: [PATCH 112/272] markdown.ex: Make suggestion(s) plural only if on >1 --- lib/pleroma/docs/markdown.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index 739e4fce3..fc6389064 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -73,13 +73,15 @@ defp print_suggestions(_file, nil), do: nil defp print_suggestions(_file, ""), do: nil defp print_suggestions(file, suggestions) do - IO.write(file, "Suggestions:\n") - if length(suggestions) > 1 do + IO.write(file, "Suggestions:\n") + for suggestion <- suggestions do print_suggestion(file, suggestion, true) end else + IO.write(file, "Suggestion:\n") + print_suggestion(file, List.first(suggestions)) end end From d2097fd0f5d5d6750de09243cb5720b161305790 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 22:33:32 +0200 Subject: [PATCH 113/272] markdown.ex: \n\n on >1 suggestions, 2-spaces on one --- lib/pleroma/docs/markdown.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index fc6389064..280fe0309 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -74,13 +74,13 @@ defp print_suggestions(_file, ""), do: nil defp print_suggestions(file, suggestions) do if length(suggestions) > 1 do - IO.write(file, "Suggestions:\n") + IO.write(file, "\n\nSuggestions:\n") for suggestion <- suggestions do print_suggestion(file, suggestion, true) end else - IO.write(file, "Suggestion:\n") + IO.write(file, " Suggestion: ") print_suggestion(file, List.first(suggestions)) end From 4785596a2cf638570b35afc91babbb0ac8309981 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 22:55:29 +0200 Subject: [PATCH 114/272] markdown.ex: end suggestions list with a newline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we end up with suggestion on the same level as the childs Markdown is a fuck… --- lib/pleroma/docs/markdown.ex | 2 ++ mix.exs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index 280fe0309..27be1b095 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -79,6 +79,8 @@ defp print_suggestions(file, suggestions) do for suggestion <- suggestions do print_suggestion(file, suggestion, true) end + + IO.write(file, "\n") else IO.write(file, " Suggestion: ") diff --git a/mix.exs b/mix.exs index 58d1606d3..e4fe5adf4 100644 --- a/mix.exs +++ b/mix.exs @@ -174,7 +174,8 @@ defp aliases do "ecto.rollback": ["pleroma.ecto.rollback"], "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], "ecto.reset": ["ecto.drop", "ecto.setup"], - test: ["ecto.create --quiet", "ecto.migrate", "test"] + test: ["ecto.create --quiet", "ecto.migrate", "test"], + docs: ["pleroma.docs", "docs"] ] end From e501c822c98edb675b71b25d165fdf8df8447c27 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 17 Sep 2019 23:02:24 +0200 Subject: [PATCH 115/272] markdown.ex: put two-spaces before the description-newline --- lib/pleroma/docs/markdown.ex | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex index 27be1b095..68b106499 100644 --- a/lib/pleroma/docs/markdown.ex +++ b/lib/pleroma/docs/markdown.ex @@ -47,12 +47,12 @@ def process(descriptions) do defp print_child_header(file, %{key: key, type: type, description: description} = _child) do IO.write( file, - "- `#{inspect(key)}` (`#{inspect(type)}`): #{description}\n" + "- `#{inspect(key)}` (`#{inspect(type)}`): #{description} \n" ) end defp print_child_header(file, %{key: key, type: type} = _child) do - IO.write(file, "- `#{inspect(key)}` (`#{inspect(type)}`)\n") + IO.write(file, "- `#{inspect(key)}` (`#{inspect(type)}`) \n") end defp print_suggestion(file, suggestion) when is_list(suggestion) do @@ -74,13 +74,11 @@ defp print_suggestions(_file, ""), do: nil defp print_suggestions(file, suggestions) do if length(suggestions) > 1 do - IO.write(file, "\n\nSuggestions:\n") + IO.write(file, "Suggestions:\n") for suggestion <- suggestions do print_suggestion(file, suggestion, true) end - - IO.write(file, "\n") else IO.write(file, " Suggestion: ") From ea6d4137dac60ae23e15ab29901a84d8468baf3e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 17 Sep 2019 21:24:21 +0000 Subject: [PATCH 116/272] Apply suggestion to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f0d55e9b..f3f38b817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -131,7 +131,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Removed - Federation: Remove `likes` from objects. -- ActivityPub: The `accept_blocks` configuration setting. +- **Breaking:** ActivityPub: The `accept_blocks` configuration setting. ## [1.0.4] - 2019-08-01 ### Fixed From 4faf2b1555f004664005e0efddb9815ebca4c5c7 Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 6 Sep 2019 17:14:31 +0300 Subject: [PATCH 117/272] post for creating invite tokens in admin api --- CHANGELOG.md | 4 ++ docs/api/admin_api.md | 16 ++++++- .../web/admin_api/admin_api_controller.ex | 18 ++++++-- lib/pleroma/web/router.ex | 2 +- .../admin_api/admin_api_controller_test.exs | 46 +++++++------------ 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3f38b817..a8342b16c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config - **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired - **Breaking:** `/api/pleroma/notifications/read` is moved to `/api/v1/pleroma/notifications/read` and now supports `max_id` and responds with Mastodon API entities. +- **Breaking:** `/api/pleroma/admin/users/invite_token` now uses `POST`, changed accepted params and returns full invite in json instead of only token string. - Configuration: added `config/description.exs`, from which `docs/config.md` is generated +- Configuration: OpenGraph and TwitterCard providers enabled by default +- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text +- Mastodon API: `pleroma.thread_muted` key in the Status entity - Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set - NodeInfo: Return `skipThreadContainment` in `metadata` for the `skip_thread_containment` option - NodeInfo: Return `mailerEnabled` in `metadata` diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 9362e3d78..a8c75d93f 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -226,13 +226,25 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ### Get an account registration invite token -- Methods: `GET` +- Methods: `POST` - Params: - *optional* `invite` => [ - *optional* `max_use` (integer) - *optional* `expires_at` (date string e.g. "2019-04-07") ] -- Response: invite token (base64 string) +- Response: + +```json +{ + "id": integer, + "token": string, + "used": boolean, + "expires_at": date, + "uses": integer, + "max_use": integer, + "invite_type": string (possible values: `one_time`, `reusable`, `date_limited`, `reusable_date_limited`) +} +``` ## `/api/pleroma/admin/users/invites` diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 2a1cc59e5..41ded7343 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -402,11 +402,21 @@ def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) @doc "Get a account registeration invite token (base64 string)" def get_invite_token(conn, params) do - options = params["invite"] || %{} - {:ok, invite} = UserInviteToken.create_invite(options) + opts = %{} - conn - |> json(invite.token) + opts = + if params["max_use"], + do: Map.put(opts, :max_use, params["max_use"]), + else: opts + + opts = + if params["expires_at"], + do: Map.put(opts, :expires_at, params["expires_at"]), + else: opts + + {:ok, invite} = UserInviteToken.create_invite(opts) + + json(conn, AccountView.render("invite.json", %{invite: invite})) end @doc "Get list of created invites" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 401133bf3..5779d27d2 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -180,7 +180,7 @@ defmodule Pleroma.Web.Router do post("/relay", AdminAPIController, :relay_follow) delete("/relay", AdminAPIController, :relay_unfollow) - get("/users/invite_token", AdminAPIController, :get_invite_token) + post("/users/invite_token", AdminAPIController, :get_invite_token) get("/users/invites", AdminAPIController, :invites) post("/users/revoke_invite", AdminAPIController, :revoke_invite) post("/users/email_invite", AdminAPIController, :email_invite) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index c497ea098..5f36d42e4 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -574,18 +574,6 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn, user: us end end - test "/api/pleroma/admin/users/invite_token" do - admin = insert(:user, info: %{is_admin: true}) - - conn = - build_conn() - |> assign(:user, admin) - |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/invite_token") - - assert conn.status == 200 - end - test "/api/pleroma/admin/users/:nickname/password_reset" do admin = insert(:user, info: %{is_admin: true}) user = insert(:user) @@ -1064,7 +1052,7 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do "@#{admin.nickname} deactivated user @#{user.nickname}" end - describe "GET /api/pleroma/admin/users/invite_token" do + describe "POST /api/pleroma/admin/users/invite_token" do setup do admin = insert(:user, info: %{is_admin: true}) @@ -1076,10 +1064,10 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do end test "without options", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/users/invite_token") + conn = post(conn, "/api/pleroma/admin/users/invite_token") - token = json_response(conn, 200) - invite = UserInviteToken.find_by_token!(token) + invite_json = json_response(conn, 200) + invite = UserInviteToken.find_by_token!(invite_json["token"]) refute invite.used refute invite.expires_at refute invite.max_use @@ -1088,12 +1076,12 @@ test "without options", %{conn: conn} do test "with expires_at", %{conn: conn} do conn = - get(conn, "/api/pleroma/admin/users/invite_token", %{ - "invite" => %{"expires_at" => Date.to_string(Date.utc_today())} + post(conn, "/api/pleroma/admin/users/invite_token", %{ + "expires_at" => Date.to_string(Date.utc_today()) }) - token = json_response(conn, 200) - invite = UserInviteToken.find_by_token!(token) + invite_json = json_response(conn, 200) + invite = UserInviteToken.find_by_token!(invite_json["token"]) refute invite.used assert invite.expires_at == Date.utc_today() @@ -1102,13 +1090,10 @@ test "with expires_at", %{conn: conn} do end test "with max_use", %{conn: conn} do - conn = - get(conn, "/api/pleroma/admin/users/invite_token", %{ - "invite" => %{"max_use" => 150} - }) + conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150}) - token = json_response(conn, 200) - invite = UserInviteToken.find_by_token!(token) + invite_json = json_response(conn, 200) + invite = UserInviteToken.find_by_token!(invite_json["token"]) refute invite.used refute invite.expires_at assert invite.max_use == 150 @@ -1117,12 +1102,13 @@ test "with max_use", %{conn: conn} do test "with max use and expires_at", %{conn: conn} do conn = - get(conn, "/api/pleroma/admin/users/invite_token", %{ - "invite" => %{"max_use" => 150, "expires_at" => Date.to_string(Date.utc_today())} + post(conn, "/api/pleroma/admin/users/invite_token", %{ + "max_use" => 150, + "expires_at" => Date.to_string(Date.utc_today()) }) - token = json_response(conn, 200) - invite = UserInviteToken.find_by_token!(token) + invite_json = json_response(conn, 200) + invite = UserInviteToken.find_by_token!(invite_json["token"]) refute invite.used assert invite.expires_at == Date.utc_today() assert invite.max_use == 150 From 2263c8b6b9260bee7dedeaff3d2ce955df12f08b Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 6 Sep 2019 17:20:44 +0300 Subject: [PATCH 118/272] little fixes --- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 41ded7343..d25c21e33 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -400,7 +400,7 @@ def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) end end - @doc "Get a account registeration invite token (base64 string)" + @doc "Get an account registration invite token" def get_invite_token(conn, params) do opts = %{} From 17ff63b3c34e6e70580be98e71b353d1f0684222 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 7 Sep 2019 08:56:22 +0300 Subject: [PATCH 119/272] docs fix --- docs/api/admin_api.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index a8c75d93f..577f802ac 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -228,10 +228,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Methods: `POST` - Params: - - *optional* `invite` => [ - - *optional* `max_use` (integer) - - *optional* `expires_at` (date string e.g. "2019-04-07") - ] + - *optional* `max_use` (integer) + - *optional* `expires_at` (date string e.g. "2019-04-07") - Response: ```json From a18f1e7cd7addf8aee9c56643f4f0531e1c5b5a0 Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 13 Sep 2019 08:07:29 +0300 Subject: [PATCH 120/272] namings --- docs/api/admin_api.md | 2 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 4 ++-- lib/pleroma/web/router.ex | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 577f802ac..7637fa0d4 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -224,7 +224,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ## `/api/pleroma/admin/users/invite_token` -### Get an account registration invite token +### Create an account registration invite token - Methods: `POST` - Params: diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index d25c21e33..8a8091daa 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -400,8 +400,8 @@ def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) end end - @doc "Get an account registration invite token" - def get_invite_token(conn, params) do + @doc "Create an account registration invite token" + def create_invite_token(conn, params) do opts = %{} opts = diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 5779d27d2..b9b85fd67 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -180,7 +180,7 @@ defmodule Pleroma.Web.Router do post("/relay", AdminAPIController, :relay_follow) delete("/relay", AdminAPIController, :relay_unfollow) - post("/users/invite_token", AdminAPIController, :get_invite_token) + post("/users/invite_token", AdminAPIController, :create_invite_token) get("/users/invites", AdminAPIController, :invites) post("/users/revoke_invite", AdminAPIController, :revoke_invite) post("/users/email_invite", AdminAPIController, :email_invite) From 384b7dd40dd484146d267ba4e12f750184365bfc Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 18 Sep 2019 18:06:49 +0300 Subject: [PATCH 121/272] Fix response --- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 4421b30c8..54ab6e032 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -438,7 +438,7 @@ def get_password_reset(conn, %{"nickname" => nickname}) do conn |> json(%{ token: token.token, - link: "#{protocol}://#{host}/api/pleroma/password_reset/#{token}" + link: "#{protocol}://#{host}/api/pleroma/password_reset/#{token.token}" }) end From 7ef575d11e46247d1f64dd09d992e532cb8c5c37 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 18:13:21 +0300 Subject: [PATCH 122/272] Initial poll refresh support Implement refreshing the object with an interval and call the function when getting the poll. --- lib/pleroma/object.ex | 18 ++++ lib/pleroma/object/fetcher.ex | 17 +++- .../controllers/mastodon_api_controller.ex | 2 +- test/fixtures/tesla_mock/poll_modified.json | 1 + test/fixtures/tesla_mock/poll_original.json | 1 + test/fixtures/tesla_mock/rin.json | 1 + test/object_test.exs | 86 +++++++++++++++++++ test/support/http_request_mock.ex | 4 + 8 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/tesla_mock/poll_modified.json create mode 100644 test/fixtures/tesla_mock/poll_original.json create mode 100644 test/fixtures/tesla_mock/rin.json diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 5033798ae..640e068e5 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -38,6 +38,24 @@ def change(struct, params \\ %{}) do def get_by_id(nil), do: nil def get_by_id(id), do: Repo.get(Object, id) + def get_by_id_and_maybe_refetch(id, opts \\ []) do + %{updated_at: updated_at} = object = get_by_id(id) + + if opts[:interval] && + NaiveDateTime.diff(updated_at, NaiveDateTime.utc_now()) > opts[:interval] do + case Fetcher.refetch_object(object) do + {:ok, %Object{} = object} -> + object + + e -> + Logger.error("Couldn't refresh #{object.data["id"]}:\n#{inspect(e)}") + object + end + else + object + end + end + def get_by_ap_id(nil), do: nil def get_by_ap_id(ap_id) do diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index c1795ae0f..da1ebd8b3 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -7,17 +7,19 @@ defmodule Pleroma.Object.Fetcher do alias Pleroma.Object alias Pleroma.Object.Containment alias Pleroma.Signature + alias Pleroma.Repo alias Pleroma.Web.ActivityPub.InternalFetchActor alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.OStatus require Logger - defp reinject_object(data) do + defp reinject_object(struct, data) do Logger.debug("Reinjecting object #{data["id"]}") with data <- Transmogrifier.fix_object(data), - {:ok, object} <- Object.create(data) do + changeset <- Object.change(struct, %{data: data}), + {:ok, object} <- Repo.insert_or_update(changeset) do {:ok, object} else e -> @@ -26,6 +28,15 @@ defp reinject_object(data) do end end + def refetch_object(%Object{data: %{"id" => id}} = object) do + with {:ok, data} <- fetch_and_contain_remote_object_from_id(id), + {:ok, object} <- reinject_object(object, data) do + {:ok, object} + else + e -> {:error, e} + end + end + # TODO: # This will create a Create activity, which we need internally at the moment. def fetch_object_from_id(id, options \\ []) do @@ -57,7 +68,7 @@ def fetch_object_from_id(id, options \\ []) do {:reject, nil} {:object, data, nil} -> - reinject_object(data) + reinject_object(%Object{}, data) {:normalize, object = %Object{}} -> {:ok, object} diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 060137b80..970cfd8db 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -485,7 +485,7 @@ def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do end def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Object{} = object <- Object.get_by_id(id), + with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60), %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]), true <- Visibility.visible_for_user?(activity, user) do conn diff --git a/test/fixtures/tesla_mock/poll_modified.json b/test/fixtures/tesla_mock/poll_modified.json new file mode 100644 index 000000000..1d026b592 --- /dev/null +++ b/test/fixtures/tesla_mock/poll_modified.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://patch.cx/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://patch.cx/users/rin","attachment":[],"attributedTo":"https://patch.cx/users/rin","cc":["https://patch.cx/users/rin/followers"],"closed":"2019-09-19T00:32:36.785333","content":"can you vote on this poll?","context":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","conversation":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","id":"https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d","oneOf":[{"name":"yes","replies":{"totalItems":8,"type":"Collection"},"type":"Note"},{"name":"no","replies":{"totalItems":3,"type":"Collection"},"type":"Note"}],"published":"2019-09-18T14:32:36.802152Z","sensitive":false,"summary":"","tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Question"} \ No newline at end of file diff --git a/test/fixtures/tesla_mock/poll_original.json b/test/fixtures/tesla_mock/poll_original.json new file mode 100644 index 000000000..267876b3c --- /dev/null +++ b/test/fixtures/tesla_mock/poll_original.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://patch.cx/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://patch.cx/users/rin","attachment":[],"attributedTo":"https://patch.cx/users/rin","cc":["https://patch.cx/users/rin/followers"],"closed":"2019-09-19T00:32:36.785333","content":"can you vote on this poll?","context":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","conversation":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","id":"https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d","oneOf":[{"name":"yes","replies":{"totalItems":4,"type":"Collection"},"type":"Note"},{"name":"no","replies":{"totalItems":0,"type":"Collection"},"type":"Note"}],"published":"2019-09-18T14:32:36.802152Z","sensitive":false,"summary":"","tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Question"} \ No newline at end of file diff --git a/test/fixtures/tesla_mock/rin.json b/test/fixtures/tesla_mock/rin.json new file mode 100644 index 000000000..2cf623764 --- /dev/null +++ b/test/fixtures/tesla_mock/rin.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://patch.cx/schemas/litepub-0.1.jsonld",{"@language":"und"}],"attachment":[],"endpoints":{"oauthAuthorizationEndpoint":"https://patch.cx/oauth/authorize","oauthRegistrationEndpoint":"https://patch.cx/api/v1/apps","oauthTokenEndpoint":"https://patch.cx/oauth/token","sharedInbox":"https://patch.cx/inbox"},"followers":"https://patch.cx/users/rin/followers","following":"https://patch.cx/users/rin/following","icon":{"type":"Image","url":"https://patch.cx/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg"},"id":"https://patch.cx/users/rin","image":{"type":"Image","url":"https://patch.cx/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg"},"inbox":"https://patch.cx/users/rin/inbox","manuallyApprovesFollowers":false,"name":"rinpatch","outbox":"https://patch.cx/users/rin/outbox","preferredUsername":"rin","publicKey":{"id":"https://patch.cx/users/rin#main-key","owner":"https://patch.cx/users/rin","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n"},"summary":"your friendly neighborhood pleroma developer
I like cute things and distributed systems, and really hate delete and redrafts","tag":[],"type":"Person","url":"https://patch.cx/users/rin"} \ No newline at end of file diff --git a/test/object_test.exs b/test/object_test.exs index ba96aeea4..72e36316c 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -89,4 +89,90 @@ test "does not fetch unknown objects when fetch_remote is false" do ) end end + + describe "get_by_id_and_maybe_refetch" do + test "refetches if the time since the last refetch is greater than the interval" do + mock(fn + %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} + + env -> + apply(HttpRequestMock, :request, [env]) + end) + + %Object{} = + object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + + assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 + assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + + mock(fn + %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_modified.json")} + + env -> + apply(HttpRequestMock, :request, [env]) + end) + + updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) + assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8 + assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3 + end + + test "returns the old object if refetch fails" do + mock(fn + %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} + + env -> + apply(HttpRequestMock, :request, [env]) + end) + + %Object{} = + object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + + assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 + assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + + mock(fn + %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> + %Tesla.Env{status: 404, body: ""} + + env -> + apply(HttpRequestMock, :request, [env]) + end) + + updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) + assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 + assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + end + + test "does not refetch if the time since the last refetch is greater than the interval" do + mock(fn + %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} + + env -> + apply(HttpRequestMock, :request, [env]) + end) + + %Object{} = + object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + + assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 + assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + + mock(fn + %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_modified.json")} + + env -> + apply(HttpRequestMock, :request, [env]) + end) + + updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100) + assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 + assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + end + end end diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 231e7c498..833162a61 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1004,6 +1004,10 @@ def get("https://skippers-bin.com/users/7v1w1r8ce6", _, _, _) do {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sjw.json")}} end + def get("https://patch.cx/users/rin", _, _, _) do + {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/rin.json")}} + end + def get(url, query, body, headers) do {:error, "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{ From 84a40f6f266ea651578b3d641c000a3b762fc9f3 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 18:31:24 +0300 Subject: [PATCH 123/272] Capture log in object refetch tests --- test/object_test.exs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/test/object_test.exs b/test/object_test.exs index 72e36316c..25e8d45d4 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -4,6 +4,7 @@ defmodule Pleroma.ObjectTest do use Pleroma.DataCase + import ExUnit.CaptureLog import Pleroma.Factory import Tesla.Mock alias Pleroma.Object @@ -134,17 +135,23 @@ test "returns the old object if refetch fails" do assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 - mock(fn - %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> - %Tesla.Env{status: 404, body: ""} + assert capture_log(fn -> + mock(fn + %{ + method: :get, + url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d" + } -> + %Tesla.Env{status: 404, body: ""} - env -> - apply(HttpRequestMock, :request, [env]) - end) + env -> + apply(HttpRequestMock, :request, [env]) + end) - updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) - assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 - assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) + assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 + assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + end) =~ + "[error] Couldn't refresh https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d" end test "does not refetch if the time since the last refetch is greater than the interval" do From a9c700ff1594bbd3c280dd6ac3a8dffa6ea7060b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 18:52:33 +0300 Subject: [PATCH 124/272] Fix wrong argument order when calling NaiveDateTime.diff --- lib/pleroma/object.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 640e068e5..3fa407931 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -42,7 +42,7 @@ def get_by_id_and_maybe_refetch(id, opts \\ []) do %{updated_at: updated_at} = object = get_by_id(id) if opts[:interval] && - NaiveDateTime.diff(updated_at, NaiveDateTime.utc_now()) > opts[:interval] do + NaiveDateTime.diff(NaiveDateTime.utc_now(), updated_at) > opts[:interval] do case Fetcher.refetch_object(object) do {:ok, %Object{} = object} -> object From e3f902b3a1330f942ddaf6ff7b108bba8fc3120a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 19:07:25 +0300 Subject: [PATCH 125/272] Set updated_at even if the object stayed the same --- lib/pleroma/object/fetcher.ex | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index da1ebd8b3..786e31cce 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -14,11 +14,20 @@ defmodule Pleroma.Object.Fetcher do require Logger + defp touch_changeset(changeset) do + updated_at = + NaiveDateTime.utc_now() + |> NaiveDateTime.truncate(:second) + + Ecto.Changeset.put_change(changeset, :updated_at, updated_at) + end + defp reinject_object(struct, data) do Logger.debug("Reinjecting object #{data["id"]}") with data <- Transmogrifier.fix_object(data), changeset <- Object.change(struct, %{data: data}), + changeset <- touch_changeset(changeset), {:ok, object} <- Repo.insert_or_update(changeset) do {:ok, object} else From d32894ae512c1f4cff4d967b89a0772e105d456b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 19:24:20 +0300 Subject: [PATCH 126/272] Move object internal fields to a constant --- lib/pleroma/constants.ex | 12 ++++++++++++ lib/pleroma/web/activity_pub/transmogrifier.ex | 10 +--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index ef1418543..0bf20cdd0 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -6,4 +6,16 @@ defmodule Pleroma.Constants do use Const const(as_public, do: "https://www.w3.org/ns/activitystreams#Public") + + const(object_internal_fields, + do: [ + "likes", + "like_count", + "announcements", + "announcement_count", + "emoji", + "context_id", + "deleted_activity_id" + ] + ) end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 8461b666e..9d2ddc1cd 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -979,15 +979,7 @@ def prepare_attachments(object) do defp strip_internal_fields(object) do object - |> Map.drop([ - "likes", - "like_count", - "announcements", - "announcement_count", - "emoji", - "context_id", - "deleted_activity_id" - ]) + |> Map.drop(Pleroma.Constants.object_internal_fields()) end defp strip_internal_tags(%{"tag" => tags} = object) do From eb87a86b5b3999f3e7ee119e839da3bd6d2ed4cf Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 19:53:51 +0300 Subject: [PATCH 127/272] Preserve internal fields when reinjecting --- lib/pleroma/object/fetcher.ex | 10 ++++ test/object_test.exs | 102 ++++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 43 deletions(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 786e31cce..fecc97c5e 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -13,6 +13,7 @@ defmodule Pleroma.Object.Fetcher do alias Pleroma.Web.OStatus require Logger + require Pleroma.Constants defp touch_changeset(changeset) do updated_at = @@ -22,10 +23,19 @@ defp touch_changeset(changeset) do Ecto.Changeset.put_change(changeset, :updated_at, updated_at) end + defp maybe_reinject_internal_fields(data, %{data: %{} = old_data}) do + internal_fields = Map.take(old_data, Pleroma.Constants.object_internal_fields()) + + Map.merge(data, internal_fields) + end + + defp maybe_reinject_internal_fields(data, _), do: data + defp reinject_object(struct, data) do Logger.debug("Reinjecting object #{data["id"]}") with data <- Transmogrifier.fix_object(data), + data <- maybe_reinject_internal_fields(data, struct), changeset <- Object.change(struct, %{data: data}), changeset <- touch_changeset(changeset), {:ok, object} <- Repo.insert_or_update(changeset) do diff --git a/test/object_test.exs b/test/object_test.exs index 25e8d45d4..3d64fdb49 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -7,8 +7,10 @@ defmodule Pleroma.ObjectTest do import ExUnit.CaptureLog import Pleroma.Factory import Tesla.Mock + alias Pleroma.Activity alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.Web.CommonAPI setup do mock(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -92,7 +94,7 @@ test "does not fetch unknown objects when fetch_remote is false" do end describe "get_by_id_and_maybe_refetch" do - test "refetches if the time since the last refetch is greater than the interval" do + setup do mock(fn %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} @@ -101,34 +103,41 @@ test "refetches if the time since the last refetch is greater than the interval" apply(HttpRequestMock, :request, [env]) end) + mock_modified = fn resp -> + mock(fn + %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> + resp + + env -> + apply(HttpRequestMock, :request, [env]) + end) + end + + on_exit(fn -> mock(fn env -> apply(HttpRequestMock, :request, [env]) end) end) + + [mock_modified: mock_modified] + end + + test "refetches if the time since the last refetch is greater than the interval", %{ + mock_modified: mock_modified + } do %Object{} = object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 - mock(fn - %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_modified.json")} - - env -> - apply(HttpRequestMock, :request, [env]) - end) + mock_modified.(%Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/poll_modified.json") + }) updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8 assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3 end - test "returns the old object if refetch fails" do - mock(fn - %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} - - env -> - apply(HttpRequestMock, :request, [env]) - end) - + test "returns the old object if refetch fails", %{mock_modified: mock_modified} do %Object{} = object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") @@ -136,16 +145,7 @@ test "returns the old object if refetch fails" do assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 assert capture_log(fn -> - mock(fn - %{ - method: :get, - url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d" - } -> - %Tesla.Env{status: 404, body: ""} - - env -> - apply(HttpRequestMock, :request, [env]) - end) + mock_modified.(%Tesla.Env{status: 404, body: ""}) updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 @@ -154,32 +154,48 @@ test "returns the old object if refetch fails" do "[error] Couldn't refresh https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d" end - test "does not refetch if the time since the last refetch is greater than the interval" do - mock(fn - %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} - - env -> - apply(HttpRequestMock, :request, [env]) - end) - + test "does not refetch if the time since the last refetch is greater than the interval", %{ + mock_modified: mock_modified + } do %Object{} = object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 - mock(fn - %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_modified.json")} - - env -> - apply(HttpRequestMock, :request, [env]) - end) + mock_modified.(%Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/poll_modified.json") + }) updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100) assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0 end + + test "preserves internal fields on refetch", %{mock_modified: mock_modified} do + %Object{} = + object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + + assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 + assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + + user = insert(:user) + activity = Activity.get_create_by_object_ap_id(object.data["id"]) + {:ok, _activity, object} = CommonAPI.favorite(activity.id, user) + + assert object.data["like_count"] == 1 + + mock_modified.(%Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/poll_modified.json") + }) + + updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) + assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8 + assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3 + + assert updated_object.data["like_count"] == 1 + end end end From c096dd86e5e4e3bdb9aa35c2c4f499efc17ddd16 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 19:59:23 +0300 Subject: [PATCH 128/272] Do not refetch local objects --- lib/pleroma/object/fetcher.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index fecc97c5e..91e6b6dca 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -48,10 +48,12 @@ defp reinject_object(struct, data) do end def refetch_object(%Object{data: %{"id" => id}} = object) do - with {:ok, data} <- fetch_and_contain_remote_object_from_id(id), + with {:local, false} <- {:local, String.starts_with?(id, Pleroma.Web.base_url() <> "/")}, + {:ok, data} <- fetch_and_contain_remote_object_from_id(id), {:ok, object} <- reinject_object(object, data) do {:ok, object} else + {:local, true} -> object e -> {:error, e} end end From 5028b7b5780fbfd0904b2e48c05a05eeab0e623d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 22:09:03 +0300 Subject: [PATCH 129/272] Fix credo issues --- lib/pleroma/object/fetcher.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 91e6b6dca..cea33b5af 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -6,8 +6,8 @@ defmodule Pleroma.Object.Fetcher do alias Pleroma.HTTP alias Pleroma.Object alias Pleroma.Object.Containment - alias Pleroma.Signature alias Pleroma.Repo + alias Pleroma.Signature alias Pleroma.Web.ActivityPub.InternalFetchActor alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.OStatus From a12aeb09c42f1c120b78d517cfbad2fe29c88006 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 18 Sep 2019 23:34:13 +0300 Subject: [PATCH 130/272] Cleanup uploads after the tests are finished --- test/test_helper.exs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_helper.exs b/test/test_helper.exs index a927b2c3d..6a389365f 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -7,3 +7,8 @@ Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual) Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client) {:ok, _} = Application.ensure_all_started(:ex_machina) + +ExUnit.after_suite(fn _results -> + uploads = Pleroma.Config.get([Pleroma.Uploaders.Local, :uploads], "test/uploads") + File.rm_rf!(uploads) +end) From a22b87b30c8bf5a28465c732ac77c70631ddc4d9 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 19 Sep 2019 00:00:05 +0300 Subject: [PATCH 131/272] Add a changelog entry for poll refetching --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3f38b817..6a49bc4dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Added +- Refreshing poll results for remote polls ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) - Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) From 6a42641b8d806f40f697303995fb12af39a93bd8 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Sat, 10 Aug 2019 21:46:36 +0300 Subject: [PATCH 132/272] Add pack.toml loading --- lib/pleroma/emoji.ex | 41 ++++++++++++++++++++++++++++------------- mix.exs | 1 + mix.lock | 1 + 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 66e20f0e4..ede734a53 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -143,23 +143,38 @@ defp load do defp load_pack(pack_dir, emoji_groups) do pack_name = Path.basename(pack_dir) - emoji_txt = Path.join(pack_dir, "emoji.txt") + pack_toml = Path.join(pack_dir, "pack.toml") - if File.exists?(emoji_txt) do - load_from_file(emoji_txt, emoji_groups) - else - extensions = Pleroma.Config.get([:emoji, :pack_extensions]) + if File.exists?(pack_toml) do + toml = Toml.decode_file!(pack_toml) - Logger.info( - "No emoji.txt found for pack \"#{pack_name}\", assuming all #{Enum.join(extensions, ", ")} files are emoji" - ) - - make_shortcode_to_file_map(pack_dir, extensions) - |> Enum.map(fn {shortcode, rel_file} -> + toml["files"] + |> Enum.map(fn {name, rel_file} -> filename = Path.join("/emoji/#{pack_name}", rel_file) - - {shortcode, filename, [to_string(match_extra(emoji_groups, filename))]} + {name, filename, pack_name} end) + else + # Load from emoji.txt / all files + emoji_txt = Path.join(pack_dir, "emoji.txt") + + if File.exists?(emoji_txt) do + load_from_file(emoji_txt, emoji_groups) + else + extensions = Pleroma.Config.get([:emoji, :pack_extensions]) + + Logger.info( + "No emoji.txt found for pack \"#{pack_name}\", assuming all #{ + Enum.join(extensions, ", ") + } files are emoji" + ) + + make_shortcode_to_file_map(pack_dir, extensions) + |> Enum.map(fn {shortcode, rel_file} -> + filename = Path.join("/emoji/#{pack_name}", rel_file) + + {shortcode, filename, [to_string(match_extra(emoji_groups, filename))]} + end) + end end end diff --git a/mix.exs b/mix.exs index f2635da24..172f3a940 100644 --- a/mix.exs +++ b/mix.exs @@ -157,6 +157,7 @@ defp deps do {:ex_rated, "~> 1.3"}, {:ex_const, "~> 0.2"}, {:plug_static_index_html, "~> 1.0.0"}, + {:toml, "~> 0.5"}, {:excoveralls, "~> 0.11.1", only: :test}, {:mox, "~> 0.5", only: :test} ] ++ oauth_deps() diff --git a/mix.lock b/mix.lock index 24b34c09c..39b9fa930 100644 --- a/mix.lock +++ b/mix.lock @@ -92,6 +92,7 @@ "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, "tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, + "toml": {:hex, :toml, "0.5.2", "e471388a8726d1ce51a6b32f864b8228a1eb8edc907a0edf2bb50eab9321b526", [:mix], [], "hexpm"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "tzdata": {:hex, :tzdata, "0.5.21", "8cbf3607fcce69636c672d5be2bbb08687fe26639a62bdcc283d267277db7cf0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "ueberauth": {:hex, :ueberauth, "0.6.1", "9e90d3337dddf38b1ca2753aca9b1e53d8a52b890191cdc55240247c89230412", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, From b791a0865641eb8210380e22e04a9fb680a79dcb Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Sun, 11 Aug 2019 00:39:21 +0300 Subject: [PATCH 133/272] Implement API actions on packs That incldues listing them and downloading them from other instances or from the remote url --- .../web/emoji_api/emoji_api_controller.ex | 171 ++++++++++++++++++ lib/pleroma/web/router.ex | 22 +++ 2 files changed, 193 insertions(+) create mode 100644 lib/pleroma/web/emoji_api/emoji_api_controller.ex diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex new file mode 100644 index 000000000..49d671518 --- /dev/null +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -0,0 +1,171 @@ +defmodule Pleroma.Web.EmojiAPI.EmojiAPIController do + use Pleroma.Web, :controller + + def reload(conn, _params) do + Pleroma.Emoji.reload() + + conn |> json("ok") + end + + @emoji_dir_path Path.join( + Pleroma.Config.get!([:instance, :static_dir]), + "emoji" + ) + + def list_packs(conn, _params) do + pack_infos = + case File.ls(@emoji_dir_path) do + {:error, _} -> + %{} + + {:ok, results} -> + results + |> Enum.filter(fn file -> + dir_path = Path.join(@emoji_dir_path, file) + # Filter to only use the pack.toml packs + File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.toml")) + end) + |> Enum.map(fn pack_name -> + pack_path = Path.join(@emoji_dir_path, pack_name) + pack_file = Path.join(pack_path, "pack.toml") + + {pack_name, Toml.decode_file!(pack_file)} + end) + # Transform into a map of pack-name => pack-data + # Check if all the files are in place and can be sent + |> Enum.map(fn {name, pack} -> + pack_path = Path.join(@emoji_dir_path, name) + + archive_for_sha = make_archive(name, pack, pack_path) + archive_sha = :crypto.hash(:sha256, archive_for_sha) |> Base.encode16() + + {name, + pack + |> put_in(["pack", "can-download"], can_download?(pack, pack_path)) + |> put_in(["pack", "download-sha256"], archive_sha)} + end) + |> Enum.into(%{}) + end + + conn |> json(pack_infos) + end + + defp can_download?(pack, pack_path) do + # If the pack is set as shared, check if it can be downloaded + # That means that when asked, the pack can be packed and sent to the remote + # Otherwise, they'd have to download it from external-src + pack["pack"]["share-files"] and + Enum.all?(pack["files"], fn {_, path} -> + File.exists?(Path.join(pack_path, path)) + end) + end + + defp make_archive(name, pack, pack_dir) do + files = + ['pack.toml'] ++ + (pack["files"] |> Enum.map(fn {_, path} -> to_charlist(path) end)) + + {:ok, {_, zip_result}} = :zip.zip('#{name}.zip', files, [:memory, cwd: to_charlist(pack_dir)]) + + zip_result + end + + def download_shared(conn, %{"name" => name}) do + pack_dir = Path.join(@emoji_dir_path, name) + pack_toml = Path.join(pack_dir, "pack.toml") + + if File.exists?(pack_toml) do + pack = Toml.decode_file!(pack_toml) + + if can_download?(pack, pack_dir) do + zip_result = make_archive(name, pack, pack_dir) + + conn + |> send_download({:binary, zip_result}, filename: "#{name}.zip") + else + {:error, + conn + |> put_status(:forbidden) + |> json("Pack #{name} cannot be downloaded from this instance, either pack sharing\ + was disabled for this pack or some files are missing")} + end + else + {:error, + conn + |> put_status(:not_found) + |> json("Pack #{name} does not exist")} + end + end + + def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do + list_uri = "#{address}/api/pleroma/emoji/packs/list" + + list = Tesla.get!(list_uri).body |> Jason.decode!() + full_pack = list[name] + pfiles = full_pack["files"] + pack = full_pack["pack"] + + pack_info_res = + cond do + pack["share-files"] && pack["can-download"] -> + {:ok, + %{ + sha: pack["download-sha256"], + uri: "#{address}/api/pleroma/emoji/packs/download_shared/#{name}" + }} + + pack["fallback-src"] -> + {:ok, + %{ + sha: pack["fallback-src-sha256"], + uri: pack["fallback-src"], + fallback: true + }} + + true -> + {:error, "The pack was not set as shared and the is no fallback url to download from"} + end + + case pack_info_res do + {:ok, %{sha: sha, uri: uri} = pinfo} -> + sha = Base.decode16!(sha) + emoji_archive = Tesla.get!(uri).body + + got_sha = :crypto.hash(:sha256, emoji_archive) + + if got_sha == sha do + local_name = data["as"] || name + pack_dir = Path.join(@emoji_dir_path, local_name) + File.mkdir_p!(pack_dir) + + files = + ['pack.toml'] ++ + (pfiles |> Enum.map(fn {_, path} -> to_charlist(path) end)) + + {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) + + # Fallback URL might not contain a pack.toml file, if that happens - fail (for now) + # FIXME: there seems to be a lack of any kind of encoders besides JSON. + erres = + if pinfo[:fallback] do + toml_path = Path.join(pack_dir, "pack.toml") + + unless File.exists?(toml_path) do + conn + |> put_status(:internal_server_error) + |> text("No pack.toml in falblack source") + end + end + + if not is_nil(erres), do: erres, else: conn |> text("ok") + else + conn + |> put_status(:internal_server_error) + |> text("SHA256 for the pack doesn't match the one sent by the server") + end + + {:error, e} -> + conn |> put_status(:internal_server_error) |> text(e) + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b9b85fd67..514446fb3 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -207,6 +207,28 @@ defmodule Pleroma.Web.Router do get("/moderation_log", AdminAPIController, :list_log) end + scope "/api/pleroma/emoji", Pleroma.Web.EmojiAPI do + scope [] do + pipe_through([:admin_api, :oauth_write]) + + post("/reload", EmojiAPIController, :reload) + end + + scope "/packs" do + # Modifying packs + pipe_through([:admin_api, :oauth_write]) + + post("/download_from", EmojiAPIController, :download_from) + end + + scope "/packs" do + # Pack info / downloading + get("/list", EmojiAPIController, :list_packs) + get("/download_shared/:name", EmojiAPIController, :download_shared) + get("/sha_of_shared/:name", EmojiAPIController, :sha_of_shared) + end + end + scope "/", Pleroma.Web.TwitterAPI do pipe_through(:pleroma_html) From 54b8e683bce13cf67f2674ea9f56b30604b28358 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Sun, 11 Aug 2019 22:32:15 +0300 Subject: [PATCH 134/272] Swap TOML for YAML to get YAML generation for packs from fallbacks If fallback url doesn't have a pack.yml file, one from the source will be used --- lib/pleroma/emoji.ex | 8 ++--- .../web/emoji_api/emoji_api_controller.ex | 36 +++++++++---------- lib/pleroma/web/router.ex | 1 - mix.exs | 2 +- mix.lock | 3 +- 5 files changed, 23 insertions(+), 27 deletions(-) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index ede734a53..2a9f5f804 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -143,12 +143,12 @@ defp load do defp load_pack(pack_dir, emoji_groups) do pack_name = Path.basename(pack_dir) - pack_toml = Path.join(pack_dir, "pack.toml") + pack_yaml = Path.join(pack_dir, "pack.yml") - if File.exists?(pack_toml) do - toml = Toml.decode_file!(pack_toml) + if File.exists?(pack_yaml) do + yaml = RelaxYaml.Decoder.read_from_file(pack_yaml) - toml["files"] + yaml["files"] |> Enum.map(fn {name, rel_file} -> filename = Path.join("/emoji/#{pack_name}", rel_file) {name, filename, pack_name} diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 49d671518..7ef9b543d 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -22,14 +22,14 @@ def list_packs(conn, _params) do results |> Enum.filter(fn file -> dir_path = Path.join(@emoji_dir_path, file) - # Filter to only use the pack.toml packs - File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.toml")) + # Filter to only use the pack.yml packs + File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.yml")) end) |> Enum.map(fn pack_name -> pack_path = Path.join(@emoji_dir_path, pack_name) - pack_file = Path.join(pack_path, "pack.toml") + pack_file = Path.join(pack_path, "pack.yml") - {pack_name, Toml.decode_file!(pack_file)} + {pack_name, RelaxYaml.Decoder.read_from_file(pack_file)} end) # Transform into a map of pack-name => pack-data # Check if all the files are in place and can be sent @@ -62,7 +62,7 @@ defp can_download?(pack, pack_path) do defp make_archive(name, pack, pack_dir) do files = - ['pack.toml'] ++ + ['pack.yml'] ++ (pack["files"] |> Enum.map(fn {_, path} -> to_charlist(path) end)) {:ok, {_, zip_result}} = :zip.zip('#{name}.zip', files, [:memory, cwd: to_charlist(pack_dir)]) @@ -72,10 +72,10 @@ defp make_archive(name, pack, pack_dir) do def download_shared(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) - pack_toml = Path.join(pack_dir, "pack.toml") + pack_yaml = Path.join(pack_dir, "pack.yml") - if File.exists?(pack_toml) do - pack = Toml.decode_file!(pack_toml) + if File.exists?(pack_yaml) do + pack = RelaxYaml.Decoder.read_from_file(pack_yaml) if can_download?(pack, pack_dir) do zip_result = make_archive(name, pack, pack_dir) @@ -139,25 +139,21 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = File.mkdir_p!(pack_dir) files = - ['pack.toml'] ++ + ['pack.yml'] ++ (pfiles |> Enum.map(fn {_, path} -> to_charlist(path) end)) {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) - # Fallback URL might not contain a pack.toml file, if that happens - fail (for now) - # FIXME: there seems to be a lack of any kind of encoders besides JSON. - erres = - if pinfo[:fallback] do - toml_path = Path.join(pack_dir, "pack.toml") + # Fallback URL might not contain a pack.yml file. Put on we have if there's none + if pinfo[:fallback] do + yaml_path = Path.join(pack_dir, "pack.yml") - unless File.exists?(toml_path) do - conn - |> put_status(:internal_server_error) - |> text("No pack.toml in falblack source") - end + unless File.exists?(yaml_path) do + File.write!(yaml_path, RelaxYaml.Encoder.encode(full_pack, [])) end + end - if not is_nil(erres), do: erres, else: conn |> text("ok") + conn |> text("ok") else conn |> put_status(:internal_server_error) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 514446fb3..1c781d750 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -225,7 +225,6 @@ defmodule Pleroma.Web.Router do # Pack info / downloading get("/list", EmojiAPIController, :list_packs) get("/download_shared/:name", EmojiAPIController, :download_shared) - get("/sha_of_shared/:name", EmojiAPIController, :sha_of_shared) end end diff --git a/mix.exs b/mix.exs index 172f3a940..e8356d564 100644 --- a/mix.exs +++ b/mix.exs @@ -157,7 +157,7 @@ defp deps do {:ex_rated, "~> 1.3"}, {:ex_const, "~> 0.2"}, {:plug_static_index_html, "~> 1.0.0"}, - {:toml, "~> 0.5"}, + {:relax_yaml, "~> 0.1"}, {:excoveralls, "~> 0.11.1", only: :test}, {:mox, "~> 0.5", only: :test} ] ++ oauth_deps() diff --git a/mix.lock b/mix.lock index 39b9fa930..8852b5f65 100644 --- a/mix.lock +++ b/mix.lock @@ -84,6 +84,7 @@ "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, + "relax_yaml": {:hex, :relax_yaml, "0.1.4", "99e55ae80b3bd1135f4288e1ba77b816ad7de05bcb4618a1a9f983ce7c89ff32", [:mix], [{:yamerl, "~> 0.4.0", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"}, @@ -92,7 +93,6 @@ "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, "tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, - "toml": {:hex, :toml, "0.5.2", "e471388a8726d1ce51a6b32f864b8228a1eb8edc907a0edf2bb50eab9321b526", [:mix], [], "hexpm"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "tzdata": {:hex, :tzdata, "0.5.21", "8cbf3607fcce69636c672d5be2bbb08687fe26639a62bdcc283d267277db7cf0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "ueberauth": {:hex, :ueberauth, "0.6.1", "9e90d3337dddf38b1ca2753aca9b1e53d8a52b890191cdc55240247c89230412", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, @@ -100,4 +100,5 @@ "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"}, "web_push_encryption": {:hex, :web_push_encryption, "0.2.1", "d42cecf73420d9dc0053ba3299cc8c8d6ff2be2487d67ca2a57265868e4d9a98", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []}, + "yamerl": {:hex, :yamerl, "0.4.0", "ae215b1242810a9bc07716b88062f1bfe06f6bc7cf68372091f630baa536df79", [:rebar3], [], "hexpm"}, } From 7fb7dd9e0e0135af467477a66692990bdaecdbe9 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Sun, 11 Aug 2019 23:24:23 +0300 Subject: [PATCH 135/272] Only find SHA256 for packs that are shared --- .../web/emoji_api/emoji_api_controller.ex | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 7ef9b543d..915059783 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -36,13 +36,19 @@ def list_packs(conn, _params) do |> Enum.map(fn {name, pack} -> pack_path = Path.join(@emoji_dir_path, name) - archive_for_sha = make_archive(name, pack, pack_path) - archive_sha = :crypto.hash(:sha256, archive_for_sha) |> Base.encode16() + if can_download?(pack, pack_path) do + archive_for_sha = make_archive(name, pack, pack_path) + archive_sha = :crypto.hash(:sha256, archive_for_sha) |> Base.encode16() - {name, - pack - |> put_in(["pack", "can-download"], can_download?(pack, pack_path)) - |> put_in(["pack", "download-sha256"], archive_sha)} + {name, + pack + |> put_in(["pack", "can-download"], true) + |> put_in(["pack", "download-sha256"], archive_sha)} + else + {name, + pack + |> put_in(["pack", "can-download"], false)} + end end) |> Enum.into(%{}) end From 7e4c8b56eab0e92b98efbf27e373d68758de540f Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Mon, 12 Aug 2019 10:35:34 +0300 Subject: [PATCH 136/272] Add tests for emoji pack sharing --- config/test.exs | 3 +- .../instance_static/emoji/test_pack/blank.png | Bin 0 -> 95 bytes test/instance_static/emoji/test_pack/pack.yml | 13 +++ .../emoji/test_pack_nonshared/pack.yml | 13 +++ test/web/emoji_api_controller_test.exs | 98 ++++++++++++++++++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 test/instance_static/emoji/test_pack/blank.png create mode 100644 test/instance_static/emoji/test_pack/pack.yml create mode 100644 test/instance_static/emoji/test_pack_nonshared/pack.yml create mode 100644 test/web/emoji_api_controller_test.exs diff --git a/config/test.exs b/config/test.exs index df512b5d7..da2778aa7 100644 --- a/config/test.exs +++ b/config/test.exs @@ -30,7 +30,8 @@ notify_email: "noreply@example.com", skip_thread_containment: false, federating: false, - external_user_synchronization: false + external_user_synchronization: false, + static_dir: "test/instance_static/" config :pleroma, :activitypub, sign_object_fetches: false diff --git a/test/instance_static/emoji/test_pack/blank.png b/test/instance_static/emoji/test_pack/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..8f50fa02340e7e09e562f86e00b6e4bd6ad1d565 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^4Is=2Bp6=1#-sr$rjj7PU get(emoji_api_path(conn, :list_packs)) |> json_response(200) + + assert Map.has_key?(resp, "test_pack") + + pack = resp["test_pack"] + + assert Map.has_key?(pack["pack"], "download-sha256") + assert pack["pack"]["can-download"] + + assert pack["files"] == %{"blank" => "blank.png"} + + # Non-shared pack + + assert Map.has_key?(resp, "test_pack_nonshared") + + pack = resp["test_pack_nonshared"] + + refute pack["pack"]["shared"] + refute pack["pack"]["can-download"] + end + + test "downloading a shared pack from download_shared" do + conn = build_conn() + + resp = + conn + |> get(emoji_api_path(conn, :download_shared, "test_pack")) + |> response(200) + + {:ok, arch} = :zip.unzip(resp, [:memory]) + + assert Enum.find(arch, fn {n, _} -> n == 'pack.yml' end) + assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) + end + + test "downloading a shared pack from another instance via download_from" do + on_exit(fn -> + File.rm_rf!("test/instance_static/emoji/test_pack2") + end) + + mock(fn + %{ + method: :get, + url: "https://example.com/api/pleroma/emoji/packs/list" + } -> + conn = build_conn() + + conn + |> get(emoji_api_path(conn, :list_packs)) + |> json_response(200) + |> json() + + %{ + method: :get, + url: "https://example.com/api/pleroma/emoji/packs/download_shared/test_pack" + } -> + conn = build_conn() + + conn + |> get(emoji_api_path(conn, :download_shared, "test_pack")) + |> response(200) + |> text() + end) + + admin = insert(:user, info: %{is_admin: true}) + + conn = build_conn() + + assert conn + |> put_req_header("content-type", "application/json") + |> assign(:user, admin) + |> post( + emoji_api_path( + conn, + :download_from + ), + %{ + instance_address: "https://example.com", + pack_name: "test_pack", + as: "test_pack2" + } + |> Jason.encode!() + ) + |> text_response(200) == "ok" + + assert File.exists?("test/instance_static/emoji/test_pack2/pack.yml") + assert File.exists?("test/instance_static/emoji/test_pack2/blank.png") + end +end From ee620ecbf11398277551ef603355a56a53690461 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Mon, 12 Aug 2019 13:13:01 +0300 Subject: [PATCH 137/272] Add caching for emoji pack sharing --- config/config.exs | 3 +- docs/config.md | 2 + lib/pleroma/application.ex | 6 ++- .../web/emoji_api/emoji_api_controller.ex | 42 ++++++++++++++++++- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/config/config.exs b/config/config.exs index c7e0cf09f..4c758d4a0 100644 --- a/config/config.exs +++ b/config/config.exs @@ -122,7 +122,8 @@ # Put groups that have higher priority than defaults here. Example in `docs/config/custom_emoji.md` Custom: ["/emoji/*.png", "/emoji/**/*.png"] ], - default_manifest: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json" + default_manifest: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json", + shared_pack_cache_seconds_per_file: 60 config :pleroma, :uri_schemes, valid_schemes: [ diff --git a/docs/config.md b/docs/config.md index 3f37fa561..1179def56 100644 --- a/docs/config.md +++ b/docs/config.md @@ -707,6 +707,8 @@ Configure OAuth 2 provider capabilities: * `pack_extensions`: A list of file extensions for emojis, when no emoji.txt for a pack is present. Example `[".png", ".gif"]` * `groups`: Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname and the value the location or array of locations. `*` can be used as a wildcard. Example `[Custom: ["/emoji/*.png", "/emoji/custom/*.png"]]` * `default_manifest`: Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays). +* `shared_pack_cache_seconds_per_file`: When an emoji pack is shared, the archive is created and cached in + memory for this amount of seconds multiplied by the number of files. ## Database options diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index dabce771d..a339e2c48 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -102,10 +102,14 @@ defp cachex_children do build_cachex("rich_media", default_ttl: :timer.minutes(120), limit: 5000), build_cachex("scrubber", limit: 2500), build_cachex("idempotency", expiration: idempotency_expiration(), limit: 2500), - build_cachex("web_resp", limit: 2500) + build_cachex("web_resp", limit: 2500), + build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10) ] end + defp emoji_packs_expiration, + do: expiration(default: :timer.seconds(5 * 60), interval: :timer.seconds(60)) + defp idempotency_expiration, do: expiration(default: :timer.seconds(6 * 60 * 60), interval: :timer.seconds(60)) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 915059783..8219eaaa1 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -1,6 +1,8 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIController do use Pleroma.Web, :controller + require Logger + def reload(conn, _params) do Pleroma.Emoji.reload() @@ -12,6 +14,8 @@ def reload(conn, _params) do "emoji" ) + @cache_seconds_per_file Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file]) + def list_packs(conn, _params) do pack_infos = case File.ls(@emoji_dir_path) do @@ -66,13 +70,49 @@ defp can_download?(pack, pack_path) do end) end - defp make_archive(name, pack, pack_dir) do + defp create_archive_and_cache(name, pack, pack_dir, md5) do files = ['pack.yml'] ++ (pack["files"] |> Enum.map(fn {_, path} -> to_charlist(path) end)) {:ok, {_, zip_result}} = :zip.zip('#{name}.zip', files, [:memory, cwd: to_charlist(pack_dir)]) + cache_ms = :timer.seconds(@cache_seconds_per_file * Enum.count(files)) + + Cachex.put!( + :emoji_packs_cache, + name, + # if pack.yml MD5 changes, the cache is not valid anymore + %{pack_yml_md5: md5, pack_data: zip_result}, + # Add a minute to cache time for every file in the pack + ttl: cache_ms + ) + + Logger.debug("Create an archive for the '#{name}' shared emoji pack, \ +keeping it in cache for #{div(cache_ms, 1000)}s") + + zip_result + end + + defp make_archive(name, pack, pack_dir) do + # Having a different pack.yml md5 invalidates cache + pack_yml_md5 = :crypto.hash(:md5, File.read!(Path.join(pack_dir, "pack.yml"))) + + maybe_cached_pack = Cachex.get!(:emoji_packs_cache, name) + + zip_result = + if is_nil(maybe_cached_pack) do + create_archive_and_cache(name, pack, pack_dir, pack_yml_md5) + else + if maybe_cached_pack[:pack_yml_md5] == pack_yml_md5 do + Logger.debug("Using cache for the '#{name}' shared emoji pack") + + maybe_cached_pack[:pack_data] + else + create_archive_and_cache(name, pack, pack_dir, pack_yml_md5) + end + end + zip_result end From 7a0c755d0a69157868e245b35b48ed07a7dfd3c7 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Mon, 12 Aug 2019 16:43:28 +0300 Subject: [PATCH 138/272] Send ok for emoji reloading as text, not as json --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 8219eaaa1..72daccc8c 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIController do def reload(conn, _params) do Pleroma.Emoji.reload() - conn |> json("ok") + conn |> text("ok") end @emoji_dir_path Path.join( From 3a8669b48771ac4203b6abf2a372c6960d36345a Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Mon, 12 Aug 2019 17:35:25 +0300 Subject: [PATCH 139/272] Fix responses for emoji pack controlller --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 72daccc8c..f2b1e8a8d 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -88,7 +88,7 @@ defp create_archive_and_cache(name, pack, pack_dir, md5) do ttl: cache_ms ) - Logger.debug("Create an archive for the '#{name}' shared emoji pack, \ + Logger.debug("Create an archive for the '#{name}' emoji pack, \ keeping it in cache for #{div(cache_ms, 1000)}s") zip_result @@ -132,14 +132,14 @@ def download_shared(conn, %{"name" => name}) do {:error, conn |> put_status(:forbidden) - |> json("Pack #{name} cannot be downloaded from this instance, either pack sharing\ + |> text("Pack #{name} cannot be downloaded from this instance, either pack sharing\ was disabled for this pack or some files are missing")} end else {:error, conn |> put_status(:not_found) - |> json("Pack #{name} does not exist")} + |> text("Pack #{name} does not exist")} end end @@ -169,7 +169,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = }} true -> - {:error, "The pack was not set as shared and the is no fallback url to download from"} + {:error, "The pack was not set as shared and there is no fallback src to download from"} end case pack_info_res do From 2d4b8f3d20c4dbf60e52e95e77f2e77766974402 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Mon, 12 Aug 2019 18:03:59 +0300 Subject: [PATCH 140/272] Add an endpoint for deleting emoji packs --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 12 ++++++++++++ lib/pleroma/web/router.ex | 1 + test/web/emoji_api_controller_test.exs | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index f2b1e8a8d..49d970277 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -210,4 +210,16 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = conn |> put_status(:internal_server_error) |> text(e) end end + + def delete(conn, %{"name" => name}) do + pack_dir = Path.join(@emoji_dir_path, name) + + case File.rm_rf(pack_dir) do + {:ok, _} -> + conn |> text("ok") + + {:error, _} -> + conn |> put_status(:internal_server_error) |> text("Couldn't delete the pack #{name}") + end + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 1c781d750..4df0ca3c3 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -218,6 +218,7 @@ defmodule Pleroma.Web.Router do # Modifying packs pipe_through([:admin_api, :oauth_write]) + delete("/delete/:name", EmojiAPIController, :delete) post("/download_from", EmojiAPIController, :download_from) end diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index c037883ee..13a34d38d 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -42,7 +42,7 @@ test "downloading a shared pack from download_shared" do assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) end - test "downloading a shared pack from another instance via download_from" do + test "downloading a shared pack from another instance via download_from, deleting it" do on_exit(fn -> File.rm_rf!("test/instance_static/emoji/test_pack2") end) @@ -94,5 +94,12 @@ test "downloading a shared pack from another instance via download_from" do assert File.exists?("test/instance_static/emoji/test_pack2/pack.yml") assert File.exists?("test/instance_static/emoji/test_pack2/blank.png") + + assert conn + |> assign(:user, admin) + |> delete(emoji_api_path(conn, :delete, "test_pack2")) + |> response(200) == "ok" + + refute File.exists?("test/instance_static/emoji/test_pack2") end end From b0ecd412f5c499773cdc462c50d6c8104a819550 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Mon, 12 Aug 2019 18:28:05 +0300 Subject: [PATCH 141/272] Clean out old emojis on reload --- lib/pleroma/emoji.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 2a9f5f804..f56b26da2 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -122,6 +122,9 @@ defp load do fn pack -> load_pack(Path.join(emoji_dir_path, pack), emoji_groups) end ) + # Clear out old emojis + :ets.delete_all_objects(@ets) + true = :ets.insert(@ets, emojis) end From 2a94eca096f67a908410ffdd82f5bace8a3df88c Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 15 Aug 2019 11:39:39 +0300 Subject: [PATCH 142/272] Change YAML to JSON --- lib/pleroma/emoji.ex | 8 ++-- .../web/emoji_api/emoji_api_controller.ex | 40 +++++++++---------- mix.exs | 1 - mix.lock | 1 - .../instance_static/emoji/test_pack/pack.json | 16 ++++++++ test/instance_static/emoji/test_pack/pack.yml | 13 ------ .../emoji/test_pack_nonshared/pack.json | 16 ++++++++ .../emoji/test_pack_nonshared/pack.yml | 13 ------ test/web/emoji_api_controller_test.exs | 4 +- 9 files changed, 58 insertions(+), 54 deletions(-) create mode 100644 test/instance_static/emoji/test_pack/pack.json delete mode 100644 test/instance_static/emoji/test_pack/pack.yml create mode 100644 test/instance_static/emoji/test_pack_nonshared/pack.json delete mode 100644 test/instance_static/emoji/test_pack_nonshared/pack.yml diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index f56b26da2..170a7d098 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -146,12 +146,12 @@ defp load do defp load_pack(pack_dir, emoji_groups) do pack_name = Path.basename(pack_dir) - pack_yaml = Path.join(pack_dir, "pack.yml") + pack_file = Path.join(pack_dir, "pack.json") - if File.exists?(pack_yaml) do - yaml = RelaxYaml.Decoder.read_from_file(pack_yaml) + if File.exists?(pack_file) do + contents = Jason.decode!(File.read!(pack_file)) - yaml["files"] + contents["files"] |> Enum.map(fn {name, rel_file} -> filename = Path.join("/emoji/#{pack_name}", rel_file) {name, filename, pack_name} diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 49d970277..aedc70372 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -26,14 +26,14 @@ def list_packs(conn, _params) do results |> Enum.filter(fn file -> dir_path = Path.join(@emoji_dir_path, file) - # Filter to only use the pack.yml packs - File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.yml")) + # Filter to only use the pack.json packs + File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.json")) end) |> Enum.map(fn pack_name -> pack_path = Path.join(@emoji_dir_path, pack_name) - pack_file = Path.join(pack_path, "pack.yml") + pack_file = Path.join(pack_path, "pack.json") - {pack_name, RelaxYaml.Decoder.read_from_file(pack_file)} + {pack_name, Jason.decode!(File.read!(pack_file))} end) # Transform into a map of pack-name => pack-data # Check if all the files are in place and can be sent @@ -72,7 +72,7 @@ defp can_download?(pack, pack_path) do defp create_archive_and_cache(name, pack, pack_dir, md5) do files = - ['pack.yml'] ++ + ['pack.json'] ++ (pack["files"] |> Enum.map(fn {_, path} -> to_charlist(path) end)) {:ok, {_, zip_result}} = :zip.zip('#{name}.zip', files, [:memory, cwd: to_charlist(pack_dir)]) @@ -82,8 +82,8 @@ defp create_archive_and_cache(name, pack, pack_dir, md5) do Cachex.put!( :emoji_packs_cache, name, - # if pack.yml MD5 changes, the cache is not valid anymore - %{pack_yml_md5: md5, pack_data: zip_result}, + # if pack.json MD5 changes, the cache is not valid anymore + %{pack_json_md5: md5, pack_data: zip_result}, # Add a minute to cache time for every file in the pack ttl: cache_ms ) @@ -95,21 +95,21 @@ defp create_archive_and_cache(name, pack, pack_dir, md5) do end defp make_archive(name, pack, pack_dir) do - # Having a different pack.yml md5 invalidates cache - pack_yml_md5 = :crypto.hash(:md5, File.read!(Path.join(pack_dir, "pack.yml"))) + # Having a different pack.json md5 invalidates cache + pack_file_md5 = :crypto.hash(:md5, File.read!(Path.join(pack_dir, "pack.json"))) maybe_cached_pack = Cachex.get!(:emoji_packs_cache, name) zip_result = if is_nil(maybe_cached_pack) do - create_archive_and_cache(name, pack, pack_dir, pack_yml_md5) + create_archive_and_cache(name, pack, pack_dir, pack_file_md5) else - if maybe_cached_pack[:pack_yml_md5] == pack_yml_md5 do + if maybe_cached_pack[:pack_file_md5] == pack_file_md5 do Logger.debug("Using cache for the '#{name}' shared emoji pack") maybe_cached_pack[:pack_data] else - create_archive_and_cache(name, pack, pack_dir, pack_yml_md5) + create_archive_and_cache(name, pack, pack_dir, pack_file_md5) end end @@ -118,10 +118,10 @@ defp make_archive(name, pack, pack_dir) do def download_shared(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) - pack_yaml = Path.join(pack_dir, "pack.yml") + pack_file = Path.join(pack_dir, "pack.json") - if File.exists?(pack_yaml) do - pack = RelaxYaml.Decoder.read_from_file(pack_yaml) + if File.exists?(pack_file) do + pack = Jason.decode!(File.read!(pack_file)) if can_download?(pack, pack_dir) do zip_result = make_archive(name, pack, pack_dir) @@ -185,17 +185,17 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = File.mkdir_p!(pack_dir) files = - ['pack.yml'] ++ + ['pack.json'] ++ (pfiles |> Enum.map(fn {_, path} -> to_charlist(path) end)) {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) - # Fallback URL might not contain a pack.yml file. Put on we have if there's none + # Fallback URL might not contain a pack.json file. Put on we have if there's none if pinfo[:fallback] do - yaml_path = Path.join(pack_dir, "pack.yml") + pack_file_path = Path.join(pack_dir, "pack.json") - unless File.exists?(yaml_path) do - File.write!(yaml_path, RelaxYaml.Encoder.encode(full_pack, [])) + unless File.exists?(pack_file_path) do + File.write!(pack_file_path, Jason.encode!(full_pack)) end end diff --git a/mix.exs b/mix.exs index e8356d564..f2635da24 100644 --- a/mix.exs +++ b/mix.exs @@ -157,7 +157,6 @@ defp deps do {:ex_rated, "~> 1.3"}, {:ex_const, "~> 0.2"}, {:plug_static_index_html, "~> 1.0.0"}, - {:relax_yaml, "~> 0.1"}, {:excoveralls, "~> 0.11.1", only: :test}, {:mox, "~> 0.5", only: :test} ] ++ oauth_deps() diff --git a/mix.lock b/mix.lock index 8852b5f65..d27041b96 100644 --- a/mix.lock +++ b/mix.lock @@ -84,7 +84,6 @@ "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, - "relax_yaml": {:hex, :relax_yaml, "0.1.4", "99e55ae80b3bd1135f4288e1ba77b816ad7de05bcb4618a1a9f983ce7c89ff32", [:mix], [{:yamerl, "~> 0.4.0", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"}, diff --git a/test/instance_static/emoji/test_pack/pack.json b/test/instance_static/emoji/test_pack/pack.json new file mode 100644 index 000000000..1b260f0f7 --- /dev/null +++ b/test/instance_static/emoji/test_pack/pack.json @@ -0,0 +1,16 @@ +{ + "pack": { + "license": "Test license", + "homepage": "https://pleroma.social", + "description": "Test description", + + "fallblack-src": "https://example.com", + "fallback-src-sha256": "65CDCCBCA9388A68023519F997367783BE69ED42864398CAC568E56F65CE0E75", + + "share-files": true + }, + + "files": { + "blank": "blank.png" + } +} diff --git a/test/instance_static/emoji/test_pack/pack.yml b/test/instance_static/emoji/test_pack/pack.yml deleted file mode 100644 index 851b06d17..000000000 --- a/test/instance_static/emoji/test_pack/pack.yml +++ /dev/null @@ -1,13 +0,0 @@ -pack: - license: Test license - homepage: https://pleroma.social - description: Test description - - fallblack-src: https://example.com - # SHA256 of the fallback-src - fallback-src-sha256: 65CDCCBCA9388A68023519F997367783BE69ED42864398CAC568E56F65CE0E75 - - share-files: true - -files: - blank: blank.png diff --git a/test/instance_static/emoji/test_pack_nonshared/pack.json b/test/instance_static/emoji/test_pack_nonshared/pack.json new file mode 100644 index 000000000..b49b1efe7 --- /dev/null +++ b/test/instance_static/emoji/test_pack_nonshared/pack.json @@ -0,0 +1,16 @@ +{ + "pack": { + "license": "Test license", + "homepage": "https://pleroma.social", + "description": "Test description", + + "fallblack-src": "https://example.com", + "fallback-src-sha256": "65CDCCBCA9388A68023519F997367783BE69ED42864398CAC568E56F65CE0E75", + + "share-files": false + }, + + "files": { + "blank": "blank.png" + } +} diff --git a/test/instance_static/emoji/test_pack_nonshared/pack.yml b/test/instance_static/emoji/test_pack_nonshared/pack.yml deleted file mode 100644 index 45c340415..000000000 --- a/test/instance_static/emoji/test_pack_nonshared/pack.yml +++ /dev/null @@ -1,13 +0,0 @@ -pack: - license: Test license - homepage: https://pleroma.social - description: Test description - - fallblack-src: https://example.com - # SHA256 of the fallback-src - fallback-src-sha256: 65CDCCBCA9388A68023519F997367783BE69ED42864398CAC568E56F65CE0E75 - - share-files: false - -files: - blank: blank.png diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 13a34d38d..bf56c1516 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -38,7 +38,7 @@ test "downloading a shared pack from download_shared" do {:ok, arch} = :zip.unzip(resp, [:memory]) - assert Enum.find(arch, fn {n, _} -> n == 'pack.yml' end) + assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) end @@ -92,7 +92,7 @@ test "downloading a shared pack from another instance via download_from, deletin ) |> text_response(200) == "ok" - assert File.exists?("test/instance_static/emoji/test_pack2/pack.yml") + assert File.exists?("test/instance_static/emoji/test_pack2/pack.json") assert File.exists?("test/instance_static/emoji/test_pack2/blank.png") assert conn From b78973d27f0c9225104914c79cf93bf3589fe7cc Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 15 Aug 2019 11:46:03 +0300 Subject: [PATCH 143/272] fallback can't have pack.json, reflect that in code having pacj.json and sha256 in a fallback pack would cause a circular dependency of itself --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index aedc70372..3b9eab8b8 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -184,19 +184,19 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = pack_dir = Path.join(@emoji_dir_path, local_name) File.mkdir_p!(pack_dir) + # Fallback cannot contain a pack.json file files = - ['pack.json'] ++ + unless(pinfo[:fallback], do: ['pack.json'], else: []) ++ (pfiles |> Enum.map(fn {_, path} -> to_charlist(path) end)) {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) - # Fallback URL might not contain a pack.json file. Put on we have if there's none + # Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256 + # in it to depend on itself if pinfo[:fallback] do pack_file_path = Path.join(pack_dir, "pack.json") - unless File.exists?(pack_file_path) do - File.write!(pack_file_path, Jason.encode!(full_pack)) - end + File.write!(pack_file_path, Jason.encode!(full_pack)) end conn |> text("ok") From adf31d596e77ef71e2ffe80d9dc41988f6c1cfb5 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 15 Aug 2019 12:07:51 +0300 Subject: [PATCH 144/272] Add tests for downloading from fallback url --- .../emoji/test_pack_nonshared/nonshared.zip | Bin 0 -> 256 bytes .../emoji/test_pack_nonshared/pack.json | 4 +- test/web/emoji_api_controller_test.exs | 40 +++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 test/instance_static/emoji/test_pack_nonshared/nonshared.zip diff --git a/test/instance_static/emoji/test_pack_nonshared/nonshared.zip b/test/instance_static/emoji/test_pack_nonshared/nonshared.zip new file mode 100644 index 0000000000000000000000000000000000000000..148446c642ea24b494bc3e25ccd772faaf2f2a13 GIT binary patch literal 256 zcmWIWW@Zs#U|`^2I2p(9A0OT*8Uf_R12HFq3`0^*VqUghL0)=j2qy#cF4@r7Q$So= z!Og(P@`9Ox0ZhE+`B41)>7++V2?-CrektH&y2Pt+hC@XnZuhYzjGD_PDeO;RYuj`( zUAMu8(_j4f1g>LGSdR&<=@xdWn#IJs;|^bzfkATSK6P%elQ2Vo rHzSiAGcLzT0G$W{OBz8ml2chBPDOKOfHx}}NFgH-`UC0NAPxfnZrnv? literal 0 HcmV?d00001 diff --git a/test/instance_static/emoji/test_pack_nonshared/pack.json b/test/instance_static/emoji/test_pack_nonshared/pack.json index b49b1efe7..b96781f81 100644 --- a/test/instance_static/emoji/test_pack_nonshared/pack.json +++ b/test/instance_static/emoji/test_pack_nonshared/pack.json @@ -4,8 +4,8 @@ "homepage": "https://pleroma.social", "description": "Test description", - "fallblack-src": "https://example.com", - "fallback-src-sha256": "65CDCCBCA9388A68023519F997367783BE69ED42864398CAC568E56F65CE0E75", + "fallback-src": "https://nonshared-pack", + "fallback-src-sha256": "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF", "share-files": false }, diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index bf56c1516..aa30e3058 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -42,9 +42,10 @@ test "downloading a shared pack from download_shared" do assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) end - test "downloading a shared pack from another instance via download_from, deleting it" do + test "downloading shared & unshared packs from another instance via download_from, deleting them" do on_exit(fn -> File.rm_rf!("test/instance_static/emoji/test_pack2") + File.rm_rf!("test/instance_static/emoji/test_pack_nonshared2") end) mock(fn @@ -69,6 +70,12 @@ test "downloading a shared pack from another instance via download_from, deletin |> get(emoji_api_path(conn, :download_shared, "test_pack")) |> response(200) |> text() + + %{ + method: :get, + url: "https://nonshared-pack" + } -> + text(File.read!("test/instance_static/emoji/test_pack_nonshared/nonshared.zip")) end) admin = insert(:user, info: %{is_admin: true}) @@ -101,5 +108,36 @@ test "downloading a shared pack from another instance via download_from, deletin |> response(200) == "ok" refute File.exists?("test/instance_static/emoji/test_pack2") + + # non-shared, downloaded from the fallback URL + + conn = build_conn() + + assert conn + |> put_req_header("content-type", "application/json") + |> assign(:user, admin) + |> post( + emoji_api_path( + conn, + :download_from + ), + %{ + instance_address: "https://example.com", + pack_name: "test_pack_nonshared", + as: "test_pack_nonshared2" + } + |> Jason.encode!() + ) + |> text_response(200) == "ok" + + assert File.exists?("test/instance_static/emoji/test_pack_nonshared2/pack.json") + assert File.exists?("test/instance_static/emoji/test_pack_nonshared2/blank.png") + + assert conn + |> assign(:user, admin) + |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) + |> response(200) == "ok" + + refute File.exists?("test/instance_static/emoji/test_pack_nonshared2") end end From bcc0bfd0c54784fe6a7ccd88fc083bd09dca41af Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 15 Aug 2019 19:55:58 +0300 Subject: [PATCH 145/272] Add an endpoint for emoji pack metadata updating --- .../web/emoji_api/emoji_api_controller.ex | 49 ++++++++++++++++++- lib/pleroma/web/router.ex | 1 + 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 3b9eab8b8..4096ccbed 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -196,7 +196,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = if pinfo[:fallback] do pack_file_path = Path.join(pack_dir, "pack.json") - File.write!(pack_file_path, Jason.encode!(full_pack)) + File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true)) end conn |> text("ok") @@ -222,4 +222,51 @@ def delete(conn, %{"name" => name}) do conn |> put_status(:internal_server_error) |> text("Couldn't delete the pack #{name}") end end + + def update_metadata(conn, %{"name" => name, "new_data" => new_data}) do + pack_dir = Path.join(@emoji_dir_path, name) + pack_file_p = Path.join(pack_dir, "pack.json") + + full_pack = Jason.decode!(File.read!(pack_file_p)) + + new_data = + if not is_nil(new_data["fallback-src"]) and is_nil(new_data["fallback-src-sha256"]) do + pack_arch = Tesla.get!(new_data["fallback-src"]).body + + {:ok, flist} = :zip.unzip(pack_arch, [:memory]) + + # Check if all files from the pack.json are in the archive + has_all_files = + Enum.all?(full_pack["files"], fn {_, from_manifest} -> + Enum.find(flist, fn {from_archive, _} -> + to_string(from_archive) == from_manifest + end) + end) + + unless has_all_files do + {:error, + conn + |> put_status(:bad_request) + |> text("The fallback archive does not have all files specified in pack.json")} + else + fallback_sha = :crypto.hash(:sha256, pack_arch) |> Base.encode16() + + {:ok, new_data |> Map.put("fallback-src-sha256", fallback_sha)} + end + else + {:ok, new_data} + end + + case new_data do + {:ok, new_data} -> + full_pack = Map.put(full_pack, "pack", new_data) + File.write!(pack_file_p, Jason.encode!(full_pack, pretty: true)) + + # Send new data back with fallback sha filled + conn |> json(new_data) + + {:error, e} -> + e + end + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 4df0ca3c3..471d09c43 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -218,6 +218,7 @@ defmodule Pleroma.Web.Router do # Modifying packs pipe_through([:admin_api, :oauth_write]) + post("/update_metadata/:name", EmojiAPIController, :update_metadata) delete("/delete/:name", EmojiAPIController, :delete) post("/download_from", EmojiAPIController, :download_from) end From 9dc9689144a54f3e5513dd26de61ec43421d6d50 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Fri, 16 Aug 2019 13:22:14 +0300 Subject: [PATCH 146/272] Add tests for pack metadata updating --- .../instance_static/emoji/test_pack/pack.json | 3 - test/web/emoji_api_controller_test.exs | 118 ++++++++++++++++-- 2 files changed, 109 insertions(+), 12 deletions(-) diff --git a/test/instance_static/emoji/test_pack/pack.json b/test/instance_static/emoji/test_pack/pack.json index 1b260f0f7..5a8ee75f9 100644 --- a/test/instance_static/emoji/test_pack/pack.json +++ b/test/instance_static/emoji/test_pack/pack.json @@ -4,9 +4,6 @@ "homepage": "https://pleroma.social", "description": "Test description", - "fallblack-src": "https://example.com", - "fallback-src-sha256": "65CDCCBCA9388A68023519F997367783BE69ED42864398CAC568E56F65CE0E75", - "share-files": true }, diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index aa30e3058..759a4dc04 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -5,6 +5,11 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do import Pleroma.Factory + @emoji_dir_path Path.join( + Pleroma.Config.get!([:instance, :static_dir]), + "emoji" + ) + test "shared & non-shared pack information in list_packs is ok" do conn = build_conn() resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) @@ -44,8 +49,8 @@ test "downloading a shared pack from download_shared" do test "downloading shared & unshared packs from another instance via download_from, deleting them" do on_exit(fn -> - File.rm_rf!("test/instance_static/emoji/test_pack2") - File.rm_rf!("test/instance_static/emoji/test_pack_nonshared2") + File.rm_rf!("#{@emoji_dir_path}/test_pack2") + File.rm_rf!("#{@emoji_dir_path}/test_pack_nonshared2") end) mock(fn @@ -75,7 +80,7 @@ test "downloading shared & unshared packs from another instance via download_fro method: :get, url: "https://nonshared-pack" } -> - text(File.read!("test/instance_static/emoji/test_pack_nonshared/nonshared.zip")) + text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) end) admin = insert(:user, info: %{is_admin: true}) @@ -99,15 +104,15 @@ test "downloading shared & unshared packs from another instance via download_fro ) |> text_response(200) == "ok" - assert File.exists?("test/instance_static/emoji/test_pack2/pack.json") - assert File.exists?("test/instance_static/emoji/test_pack2/blank.png") + assert File.exists?("#{@emoji_dir_path}/test_pack2/pack.json") + assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png") assert conn |> assign(:user, admin) |> delete(emoji_api_path(conn, :delete, "test_pack2")) |> response(200) == "ok" - refute File.exists?("test/instance_static/emoji/test_pack2") + refute File.exists?("#{@emoji_dir_path}/test_pack2") # non-shared, downloaded from the fallback URL @@ -130,14 +135,109 @@ test "downloading shared & unshared packs from another instance via download_fro ) |> text_response(200) == "ok" - assert File.exists?("test/instance_static/emoji/test_pack_nonshared2/pack.json") - assert File.exists?("test/instance_static/emoji/test_pack_nonshared2/blank.png") + assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json") + assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png") assert conn |> assign(:user, admin) |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) |> response(200) == "ok" - refute File.exists?("test/instance_static/emoji/test_pack_nonshared2") + refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2") + end + + describe "updating pack metadata" do + setup do + pack_file = "#{@emoji_dir_path}/test_pack/pack.json" + original_content = File.read!(pack_file) + + on_exit(fn -> + File.write!(pack_file, original_content) + end) + + {:ok, + admin: insert(:user, info: %{is_admin: true}), + pack_file: pack_file, + new_data: %{ + "license" => "Test license changed", + "homepage" => "https://pleroma.social", + "description" => "Test description", + "share-files" => false + }} + end + + test "for a pack without a fallback source", ctx do + conn = build_conn() + + assert conn + |> assign(:user, ctx[:admin]) + |> post( + emoji_api_path(conn, :update_metadata, "test_pack"), + %{ + "new_data" => ctx[:new_data] + } + ) + |> json_response(200) == ctx[:new_data] + + assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] + end + + test "for a pack with a fallback source", ctx do + mock(fn + %{ + method: :get, + url: "https://nonshared-pack" + } -> + text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) + end) + + new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") + + new_data_with_sha = + Map.put( + new_data, + "fallback-src-sha256", + "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF" + ) + + conn = build_conn() + + assert conn + |> assign(:user, ctx[:admin]) + |> post( + emoji_api_path(conn, :update_metadata, "test_pack"), + %{ + "new_data" => new_data + } + ) + |> json_response(200) == new_data_with_sha + + assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha + end + + test "when the fallback source doesn't have all the files", ctx do + mock(fn + %{ + method: :get, + url: "https://nonshared-pack" + } -> + {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory]) + text(empty_arch) + end) + + new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") + + conn = build_conn() + + assert conn + |> assign(:user, ctx[:admin]) + |> post( + emoji_api_path(conn, :update_metadata, "test_pack"), + %{ + "new_data" => new_data + } + ) + |> text_response(:bad_request) =~ "does not have all" + end end end From 261d92f9c2605c720e7fce8b05025e5ac452e5c9 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Fri, 16 Aug 2019 13:30:14 +0300 Subject: [PATCH 147/272] Update the pack fallback-src sha generation condition The old one would not regenerate sha when fallback src changed --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 4096ccbed..4873129c4 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -229,8 +229,13 @@ def update_metadata(conn, %{"name" => name, "new_data" => new_data}) do full_pack = Jason.decode!(File.read!(pack_file_p)) + # The new fallback-src is in the new data and it's not the same as it was in the old data + should_update_fb_sha = + not is_nil(new_data["fallback-src"]) and + new_data["fallback-src"] != full_pack["pack"]["fallback-src"] + new_data = - if not is_nil(new_data["fallback-src"]) and is_nil(new_data["fallback-src-sha256"]) do + if should_update_fb_sha do pack_arch = Tesla.get!(new_data["fallback-src"]).body {:ok, flist} = :zip.unzip(pack_arch, [:memory]) From 9afe7258dd5ca1e5a6333a5a9f93d9ab43d4aaf4 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Sun, 18 Aug 2019 22:05:38 +0300 Subject: [PATCH 148/272] Implememt emoji pack file updating + write tests --- .../web/emoji_api/emoji_api_controller.ex | 132 +++++++++++++++++- lib/pleroma/web/router.ex | 3 +- test/web/emoji_api_controller_test.exs | 69 ++++++++- 3 files changed, 196 insertions(+), 8 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 4873129c4..dc3dcf1ea 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -223,7 +223,7 @@ def delete(conn, %{"name" => name}) do end end - def update_metadata(conn, %{"name" => name, "new_data" => new_data}) do + def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do pack_dir = Path.join(@emoji_dir_path, name) pack_file_p = Path.join(pack_dir, "pack.json") @@ -274,4 +274,134 @@ def update_metadata(conn, %{"name" => name, "new_data" => new_data}) do e end end + + def update_file( + conn, + %{"pack_name" => pack_name, "action" => action, "shortcode" => shortcode} = params + ) do + pack_dir = Path.join(@emoji_dir_path, pack_name) + pack_file_p = Path.join(pack_dir, "pack.json") + + full_pack = Jason.decode!(File.read!(pack_file_p)) + + res = + case action do + "add" -> + unless Map.has_key?(full_pack["files"], shortcode) do + with %{"file" => %Plug.Upload{filename: filename, path: upload_path}} <- params do + # If there was a file name provided with the request, use it, otherwise just use the + # uploaded file name + filename = + if Map.has_key?(params, "filename") do + params["filename"] + else + filename + end + + file_path = Path.join(pack_dir, filename) + + # If the name contains directories, create them + if String.contains?(file_path, "/") do + File.mkdir_p!(Path.dirname(file_path)) + end + + # Copy the uploaded file from the temporary directory + File.copy!(upload_path, file_path) + + updated_full_pack = put_in(full_pack, ["files", shortcode], filename) + + {:ok, updated_full_pack} + else + _ -> {:error, conn |> put_status(:bad_request) |> text("\"file\" not provided")} + end + else + {:error, + conn + |> put_status(:conflict) + |> text("An emoji with the \"#{shortcode}\" shortcode already exists")} + end + + "remove" -> + if Map.has_key?(full_pack["files"], shortcode) do + {emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) + + emoji_file_path = Path.join(pack_dir, emoji_file_path) + + # Delete the emoji file + File.rm!(emoji_file_path) + + # If the old directory has no more files, remove it + if String.contains?(emoji_file_path, "/") do + dir = Path.dirname(emoji_file_path) + + if Enum.empty?(File.ls!(dir)) do + File.rmdir!(dir) + end + end + + {:ok, updated_full_pack} + else + {:error, + conn |> put_status(:bad_request) |> text("Emoji \"#{shortcode}\" does not exist")} + end + + "update" -> + if Map.has_key?(full_pack["files"], shortcode) do + with %{"new_shortcode" => new_shortcode, "new_filename" => new_filename} <- params do + # First, remove the old shortcode, saving the old path + {old_emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) + old_emoji_file_path = Path.join(pack_dir, old_emoji_file_path) + new_emoji_file_path = Path.join(pack_dir, new_filename) + + # If the name contains directories, create them + if String.contains?(new_emoji_file_path, "/") do + File.mkdir_p!(Path.dirname(new_emoji_file_path)) + end + + # Move/Rename the old filename to a new filename + # These are probably on the same filesystem, so just rename should work + :ok = File.rename(old_emoji_file_path, new_emoji_file_path) + + # If the old directory has no more files, remove it + if String.contains?(old_emoji_file_path, "/") do + dir = Path.dirname(old_emoji_file_path) + + if Enum.empty?(File.ls!(dir)) do + File.rmdir!(dir) + end + end + + # Then, put in the new shortcode with the new path + updated_full_pack = + put_in(updated_full_pack, ["files", new_shortcode], new_filename) + + {:ok, updated_full_pack} + else + _ -> + {:error, + conn + |> put_status(:bad_request) + |> text("new_shortcode or new_file were not specified")} + end + else + {:error, + conn |> put_status(:bad_request) |> text("Emoji \"#{shortcode}\" does not exist")} + end + + _ -> + {:error, conn |> put_status(:bad_request) |> text("Unknown action: #{action}")} + end + + case res do + {:ok, updated_full_pack} -> + # Write the emoji pack file + File.write!(pack_file_p, Jason.encode!(updated_full_pack, pretty: true)) + + # Return the modified file list + conn |> json(updated_full_pack["files"]) + + {:error, e} -> + e + end + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 471d09c43..acd6f740b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -218,7 +218,8 @@ defmodule Pleroma.Web.Router do # Modifying packs pipe_through([:admin_api, :oauth_write]) - post("/update_metadata/:name", EmojiAPIController, :update_metadata) + post("/update_file/:pack_name", EmojiAPIController, :update_file) + post("/update_metadata/:pack_name", EmojiAPIController, :update_metadata) delete("/delete/:name", EmojiAPIController, :delete) post("/download_from", EmojiAPIController, :download_from) end diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 759a4dc04..6d3603da5 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -85,11 +85,10 @@ test "downloading shared & unshared packs from another instance via download_fro admin = insert(:user, info: %{is_admin: true}) - conn = build_conn() + conn = build_conn() |> assign(:user, admin) assert conn |> put_req_header("content-type", "application/json") - |> assign(:user, admin) |> post( emoji_api_path( conn, @@ -108,7 +107,6 @@ test "downloading shared & unshared packs from another instance via download_fro assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png") assert conn - |> assign(:user, admin) |> delete(emoji_api_path(conn, :delete, "test_pack2")) |> response(200) == "ok" @@ -116,11 +114,10 @@ test "downloading shared & unshared packs from another instance via download_fro # non-shared, downloaded from the fallback URL - conn = build_conn() + conn = build_conn() |> assign(:user, admin) assert conn |> put_req_header("content-type", "application/json") - |> assign(:user, admin) |> post( emoji_api_path( conn, @@ -139,7 +136,6 @@ test "downloading shared & unshared packs from another instance via download_fro assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png") assert conn - |> assign(:user, admin) |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) |> response(200) == "ok" @@ -240,4 +236,65 @@ test "when the fallback source doesn't have all the files", ctx do |> text_response(:bad_request) =~ "does not have all" end end + + test "updating pack files" do + pack_file = "#{@emoji_dir_path}/test_pack/pack.json" + original_content = File.read!(pack_file) + + on_exit(fn -> + File.write!(pack_file, original_content) + + File.rm_rf!("#{@emoji_dir_path}/test_pack/dir") + File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2") + end) + + admin = insert(:user, info: %{is_admin: true}) + + conn = build_conn() + + same_name = %{ + "action" => "add", + "shortcode" => "blank", + "filename" => "dir/blank.png", + "file" => %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_dir_path}/test_pack/blank.png" + } + } + + different_name = %{same_name | "shortcode" => "blank_2"} + + conn = conn |> assign(:user, admin) + + assert conn + |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name) + |> text_response(:conflict) =~ "already exists" + + assert conn + |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name) + |> json_response(200) == %{"blank" => "blank.png", "blank_2" => "dir/blank.png"} + + assert File.exists?("#{@emoji_dir_path}/test_pack/dir/blank.png") + + assert conn + |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ + "action" => "update", + "shortcode" => "blank_2", + "new_shortcode" => "blank_3", + "new_filename" => "dir_2/blank_3.png" + }) + |> json_response(200) == %{"blank" => "blank.png", "blank_3" => "dir_2/blank_3.png"} + + refute File.exists?("#{@emoji_dir_path}/test_pack/dir/") + assert File.exists?("#{@emoji_dir_path}/test_pack/dir_2/blank_3.png") + + assert conn + |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ + "action" => "remove", + "shortcode" => "blank_3" + }) + |> json_response(200) == %{"blank" => "blank.png"} + + refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/") + end end From 16edfef12e6781971e2056a80a0ac38dcc254b1b Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Mon, 19 Aug 2019 19:26:15 +0300 Subject: [PATCH 149/272] Handle empty shortcode/filename/new_shortcode/new_filename --- .../web/emoji_api/emoji_api_controller.ex | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index dc3dcf1ea..fdecbb700 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -298,19 +298,27 @@ def update_file( filename end - file_path = Path.join(pack_dir, filename) + unless String.trim(shortcode) |> String.length() == 0 or + String.trim(filename) |> String.length() == 0 do + file_path = Path.join(pack_dir, filename) - # If the name contains directories, create them - if String.contains?(file_path, "/") do - File.mkdir_p!(Path.dirname(file_path)) + # If the name contains directories, create them + if String.contains?(file_path, "/") do + File.mkdir_p!(Path.dirname(file_path)) + end + + # Copy the uploaded file from the temporary directory + File.copy!(upload_path, file_path) + + updated_full_pack = put_in(full_pack, ["files", shortcode], filename) + + {:ok, updated_full_pack} + else + {:error, + conn + |> put_status(:bad_request) + |> text("shortcode or filename cannot be empty")} end - - # Copy the uploaded file from the temporary directory - File.copy!(upload_path, file_path) - - updated_full_pack = put_in(full_pack, ["files", shortcode], filename) - - {:ok, updated_full_pack} else _ -> {:error, conn |> put_status(:bad_request) |> text("\"file\" not provided")} end @@ -348,34 +356,42 @@ def update_file( "update" -> if Map.has_key?(full_pack["files"], shortcode) do with %{"new_shortcode" => new_shortcode, "new_filename" => new_filename} <- params do - # First, remove the old shortcode, saving the old path - {old_emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) - old_emoji_file_path = Path.join(pack_dir, old_emoji_file_path) - new_emoji_file_path = Path.join(pack_dir, new_filename) + unless String.trim(new_shortcode) |> String.length() == 0 or + String.trim(new_filename) |> String.length() == 0 do + # First, remove the old shortcode, saving the old path + {old_emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) + old_emoji_file_path = Path.join(pack_dir, old_emoji_file_path) + new_emoji_file_path = Path.join(pack_dir, new_filename) - # If the name contains directories, create them - if String.contains?(new_emoji_file_path, "/") do - File.mkdir_p!(Path.dirname(new_emoji_file_path)) - end - - # Move/Rename the old filename to a new filename - # These are probably on the same filesystem, so just rename should work - :ok = File.rename(old_emoji_file_path, new_emoji_file_path) - - # If the old directory has no more files, remove it - if String.contains?(old_emoji_file_path, "/") do - dir = Path.dirname(old_emoji_file_path) - - if Enum.empty?(File.ls!(dir)) do - File.rmdir!(dir) + # If the name contains directories, create them + if String.contains?(new_emoji_file_path, "/") do + File.mkdir_p!(Path.dirname(new_emoji_file_path)) end + + # Move/Rename the old filename to a new filename + # These are probably on the same filesystem, so just rename should work + :ok = File.rename(old_emoji_file_path, new_emoji_file_path) + + # If the old directory has no more files, remove it + if String.contains?(old_emoji_file_path, "/") do + dir = Path.dirname(old_emoji_file_path) + + if Enum.empty?(File.ls!(dir)) do + File.rmdir!(dir) + end + end + + # Then, put in the new shortcode with the new path + updated_full_pack = + put_in(updated_full_pack, ["files", new_shortcode], new_filename) + + {:ok, updated_full_pack} + else + {:error, + conn + |> put_status(:bad_request) + |> text("new_shortcode or new_filename cannot be empty")} end - - # Then, put in the new shortcode with the new path - updated_full_pack = - put_in(updated_full_pack, ["files", new_shortcode], new_filename) - - {:ok, updated_full_pack} else _ -> {:error, From 8dbdd5c280d15fde4712989001d4ddee1cd37cff Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 20 Aug 2019 14:52:36 +0300 Subject: [PATCH 150/272] Allow uploading new emojis to packs from URLs --- .../web/emoji_api/emoji_api_controller.ex | 65 ++++++++++--------- test/web/emoji_api_controller_test.exs | 34 ++++++++++ 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index fdecbb700..87ae0e092 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -288,39 +288,44 @@ def update_file( case action do "add" -> unless Map.has_key?(full_pack["files"], shortcode) do - with %{"file" => %Plug.Upload{filename: filename, path: upload_path}} <- params do - # If there was a file name provided with the request, use it, otherwise just use the - # uploaded file name - filename = - if Map.has_key?(params, "filename") do - params["filename"] - else - filename - end - - unless String.trim(shortcode) |> String.length() == 0 or - String.trim(filename) |> String.length() == 0 do - file_path = Path.join(pack_dir, filename) - - # If the name contains directories, create them - if String.contains?(file_path, "/") do - File.mkdir_p!(Path.dirname(file_path)) - end - - # Copy the uploaded file from the temporary directory - File.copy!(upload_path, file_path) - - updated_full_pack = put_in(full_pack, ["files", shortcode], filename) - - {:ok, updated_full_pack} + filename = + if Map.has_key?(params, "filename") do + params["filename"] else - {:error, - conn - |> put_status(:bad_request) - |> text("shortcode or filename cannot be empty")} + case params["file"] do + %Plug.Upload{filename: filename} -> filename + url when is_binary(url) -> Path.basename(url) + end end + + unless String.trim(shortcode) |> String.length() == 0 or + String.trim(filename) |> String.length() == 0 do + file_path = Path.join(pack_dir, filename) + + # If the name contains directories, create them + if String.contains?(file_path, "/") do + File.mkdir_p!(Path.dirname(file_path)) + end + + case params["file"] do + %Plug.Upload{path: upload_path} -> + # Copy the uploaded file from the temporary directory + File.copy!(upload_path, file_path) + + url when is_binary(url) -> + # Download and write the file + file_contents = Tesla.get!(url).body + File.write!(file_path, file_contents) + end + + updated_full_pack = put_in(full_pack, ["files", shortcode], filename) + + {:ok, updated_full_pack} else - _ -> {:error, conn |> put_status(:bad_request) |> text("\"file\" not provided")} + {:error, + conn + |> put_status(:bad_request) + |> text("shortcode or filename cannot be empty")} end else {:error, diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 6d3603da5..c1aece691 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -244,6 +244,7 @@ test "updating pack files" do on_exit(fn -> File.write!(pack_file, original_content) + File.rm_rf!("#{@emoji_dir_path}/test_pack/blank_url.png") File.rm_rf!("#{@emoji_dir_path}/test_pack/dir") File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2") end) @@ -296,5 +297,38 @@ test "updating pack files" do |> json_response(200) == %{"blank" => "blank.png"} refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/") + + mock(fn + %{ + method: :get, + url: "https://test-blank/blank_url.png" + } -> + text(File.read!("#{@emoji_dir_path}/test_pack/blank.png")) + end) + + # The name should be inferred from the URL ending + from_url = %{ + "action" => "add", + "shortcode" => "blank_url", + "file" => "https://test-blank/blank_url.png" + } + + assert conn + |> post(emoji_api_path(conn, :update_file, "test_pack"), from_url) + |> json_response(200) == %{ + "blank" => "blank.png", + "blank_url" => "blank_url.png" + } + + assert File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") + + assert conn + |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ + "action" => "remove", + "shortcode" => "blank_url" + }) + |> json_response(200) == %{"blank" => "blank.png"} + + refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") end end From 6b4a144e4d9fa17db6fbda800511f7f41ae1c731 Mon Sep 17 00:00:00 2001 From: vaartis Date: Sat, 24 Aug 2019 21:58:21 +0000 Subject: [PATCH 151/272] Remove unused yaml dependency from mix.lock --- mix.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/mix.lock b/mix.lock index d27041b96..24b34c09c 100644 --- a/mix.lock +++ b/mix.lock @@ -99,5 +99,4 @@ "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"}, "web_push_encryption": {:hex, :web_push_encryption, "0.2.1", "d42cecf73420d9dc0053ba3299cc8c8d6ff2be2487d67ca2a57265868e4d9a98", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []}, - "yamerl": {:hex, :yamerl, "0.4.0", "ae215b1242810a9bc07716b88062f1bfe06f6bc7cf68372091f630baa536df79", [:rebar3], [], "hexpm"}, } From f5131540dc9bbf8038e6625f4524ca01b52abbbf Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 28 Aug 2019 19:29:01 +0300 Subject: [PATCH 152/272] Add a way to create emoji packs via an endpoint --- .../web/emoji_api/emoji_api_controller.ex | 21 ++++++++++++ lib/pleroma/web/router.ex | 1 + test/web/emoji_api_controller_test.exs | 34 +++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 87ae0e092..0bd9cd207 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -211,6 +211,27 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = end end + def create(conn, %{"name" => name}) do + pack_dir = Path.join(@emoji_dir_path, name) + + unless File.exists?(pack_dir) do + File.mkdir_p!(pack_dir) + + pack_file_p = Path.join(pack_dir, "pack.json") + + File.write!( + pack_file_p, + Jason.encode!(%{pack: %{}, files: %{}}) + ) + + conn |> text("ok") + else + conn + |> put_status(:conflict) + |> text("A pack named \"#{name}\" already exists") + end + end + def delete(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index acd6f740b..a21fefc70 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -220,6 +220,7 @@ defmodule Pleroma.Web.Router do post("/update_file/:pack_name", EmojiAPIController, :update_file) post("/update_metadata/:pack_name", EmojiAPIController, :update_metadata) + post("/create/:name", EmojiAPIController, :create) delete("/delete/:name", EmojiAPIController, :delete) post("/download_from", EmojiAPIController, :download_from) end diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index c1aece691..fa194a26c 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -331,4 +331,38 @@ test "updating pack files" do refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") end + + test "creating and deleting a pack" do + on_exit(fn -> + File.rm_rf!("#{@emoji_dir_path}/test_created") + end) + + admin = insert(:user, info: %{is_admin: true}) + + conn = build_conn() |> assign(:user, admin) + + assert conn + |> put_req_header("content-type", "application/json") + |> post( + emoji_api_path( + conn, + :create, + "test_created" + ) + ) + |> text_response(200) == "ok" + + assert File.exists?("#{@emoji_dir_path}/test_created/pack.json") + + assert Jason.decode!(File.read!("#{@emoji_dir_path}/test_created/pack.json")) == %{ + "pack" => %{}, + "files" => %{} + } + + assert conn + |> delete(emoji_api_path(conn, :delete, "test_created")) + |> response(200) == "ok" + + refute File.exists?("#{@emoji_dir_path}/test_created/pack.json") + end end From 13cd93a0d314238427c217ec0ab8f59f329321f5 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Sun, 1 Sep 2019 15:38:45 +0300 Subject: [PATCH 153/272] Use && insted of "and" for checking shared-files for packs share-files can be nil and "and" does not like that --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 0bd9cd207..f34a4e08c 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -64,7 +64,7 @@ defp can_download?(pack, pack_path) do # If the pack is set as shared, check if it can be downloaded # That means that when asked, the pack can be packed and sent to the remote # Otherwise, they'd have to download it from external-src - pack["pack"]["share-files"] and + pack["pack"]["share-files"] && Enum.all?(pack["files"], fn {_, path} -> File.exists?(Path.join(pack_path, path)) end) From 9eb2ee4df0478daec1172eec2289868105b72756 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 10 Sep 2019 21:16:30 +0300 Subject: [PATCH 154/272] Allow importing old (emoji.txt / plain) packs from the filesystem --- .../web/emoji_api/emoji_api_controller.ex | 66 ++++++++++++++++++ lib/pleroma/web/router.ex | 2 + .../emoji/test_pack_for_import/blank.png | Bin 0 -> 95 bytes test/web/emoji_api_controller_test.exs | 41 +++++++++++ 4 files changed, 109 insertions(+) create mode 100644 test/instance_static/emoji/test_pack_for_import/blank.png diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index f34a4e08c..dffb91b0f 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -446,4 +446,70 @@ def update_file( e end end + + def import_from_fs(conn, _params) do + case File.ls(@emoji_dir_path) do + {:error, _} -> + conn + |> put_status(:internal_server_error) + |> text("Error accessing emoji pack directory") + + {:ok, results} -> + imported_pack_names = + results + |> Enum.filter(fn file -> + dir_path = Path.join(@emoji_dir_path, file) + # Find the directories that do NOT have pack.json + File.dir?(dir_path) and not File.exists?(Path.join(dir_path, "pack.json")) + end) + |> Enum.map(fn dir -> + dir_path = Path.join(@emoji_dir_path, dir) + emoji_txt_path = Path.join(dir_path, "emoji.txt") + + files_for_pack = + if File.exists?(emoji_txt_path) do + # There's an emoji.txt file, it's likely from a pack installed by the pack manager. + # Make a pack.json file from the contents of that emoji.txt fileh + + # FIXME: Copy-pasted from Pleroma.Emoji/load_from_file_stream/2 + + # Create a map of shortcodes to filenames from emoji.txt + + File.read!(emoji_txt_path) + |> String.split("\n") + |> Enum.map(&String.trim/1) + |> Enum.map(fn line -> + case String.split(line, ~r/,\s*/) do + # This matches both strings with and without tags and we don't care about tags here + [name, file | _] -> + {name, file} + + _ -> + nil + end + end) + |> Enum.filter(fn x -> not is_nil(x) end) + |> Enum.into(%{}) + else + # If there's no emoji.txt, assume all files that are of certain extensions from the config + # are emojis and import them all + Pleroma.Emoji.make_shortcode_to_file_map( + dir_path, + Pleroma.Config.get!([:emoji, :pack_extensions]) + ) + end + + pack_json_contents = Jason.encode!(%{pack: %{}, files: files_for_pack}) + + File.write!( + Path.join(dir_path, "pack.json"), + pack_json_contents + ) + + dir + end) + + conn |> json(imported_pack_names) + end + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a21fefc70..1252048f0 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -218,6 +218,8 @@ defmodule Pleroma.Web.Router do # Modifying packs pipe_through([:admin_api, :oauth_write]) + post("/import_from_fs", EmojiAPIController, :import_from_fs) + post("/update_file/:pack_name", EmojiAPIController, :update_file) post("/update_metadata/:pack_name", EmojiAPIController, :update_metadata) post("/create/:name", EmojiAPIController, :create) diff --git a/test/instance_static/emoji/test_pack_for_import/blank.png b/test/instance_static/emoji/test_pack_for_import/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..8f50fa02340e7e09e562f86e00b6e4bd6ad1d565 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^4Is=2Bp6=1#-sr$rjj7PU + File.rm!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt") + File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") + end) + + conn = build_conn() + resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + + refute Map.has_key?(resp, "test_pack_for_import") + + admin = insert(:user, info: %{is_admin: true}) + + assert conn + |> assign(:user, admin) + |> post(emoji_api_path(conn, :import_from_fs)) + |> json_response(200) == ["test_pack_for_import"] + + resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} + + File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") + refute File.exists?("#{@emoji_dir_path}/test_pack_for_import/pack.json") + + emoji_txt_content = "blank, blank.png, Fun\n\nblank2, blank.png" + + File.write!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt", emoji_txt_content) + + assert conn + |> assign(:user, admin) + |> post(emoji_api_path(conn, :import_from_fs)) + |> json_response(200) == ["test_pack_for_import"] + + resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + + assert resp["test_pack_for_import"]["files"] == %{ + "blank" => "blank.png", + "blank2" => "blank.png" + } + end end From 87057101b0e14eb51ff9367dfe9c5522ea933161 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 10 Sep 2019 21:34:57 +0300 Subject: [PATCH 155/272] Add documentation for the emoji api endpoints --- .../web/emoji_api/emoji_api_controller.ex | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index dffb91b0f..dc676b00f 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -16,6 +16,12 @@ def reload(conn, _params) do @cache_seconds_per_file Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file]) + @doc """ + Lists the packs available on the instance as JSON. + + The information is public and does not require authentification. The format is + a map of "pack directory name" to pack.json contents. + """ def list_packs(conn, _params) do pack_infos = case File.ls(@emoji_dir_path) do @@ -116,6 +122,10 @@ defp make_archive(name, pack, pack_dir) do zip_result end + @doc """ + An endpoint for other instances (via admin UI) or users (via browser) + to download packs that the instance shares. + """ def download_shared(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) pack_file = Path.join(pack_dir, "pack.json") @@ -143,6 +153,13 @@ def download_shared(conn, %{"name" => name}) do end end + @doc """ + An admin endpoint to request downloading a pack named `pack_name` from the instance + `instance_address`. + + If the requested instance's admin chose to share the pack, it will be downloaded + from that instance, otherwise it will be downloaded from the fallback source, if there is one. + """ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do list_uri = "#{address}/api/pleroma/emoji/packs/list" @@ -211,6 +228,9 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = end end + @doc """ + Creates an empty pack named `name` which then can be updated via the admin UI. + """ def create(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) @@ -232,6 +252,9 @@ def create(conn, %{"name" => name}) do end end + @doc """ + Deletes the pack `name` and all it's files. + """ def delete(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) @@ -244,6 +267,11 @@ def delete(conn, %{"name" => name}) do end end + @doc """ + An endpoint to update `pack_names`'s metadata. + + `new_data` is the new metadata for the pack, that will replace the old metadata. + """ def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do pack_dir = Path.join(@emoji_dir_path, name) pack_file_p = Path.join(pack_dir, "pack.json") @@ -296,6 +324,20 @@ def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do end end + @doc """ + Updates a file in a pack. + + Updating can mean three things: + + - `add` adds an emoji named `shortcode` to the pack `pack_name`, + that means that the emoji file needs to be uploaded with the request + (thus requiring it to be a multipart request) and be named `file`. + There can also be an optional `filename` that will be the new emoji file name + (if it's not there, the name will be taken from the uploaded file). + - `update` changes emoji shortcode (from `shortcode` to `new_shortcode` or moves the file + (from the current filename to `new_filename`) + - `remove` removes the emoji named `shortcode` and it's associated file + """ def update_file( conn, %{"pack_name" => pack_name, "action" => action, "shortcode" => shortcode} = params @@ -447,6 +489,16 @@ def update_file( end end + @doc """ + Imports emoji from the filesystem. + + Importing means checking all the directories in the + `$instance_static/emoji/` for directories which do not have + `pack.json`. If one has an emoji.txt file, that file will be used + to create a `pack.json` file with it's contents. If the directory has + neither, all the files with specific configured extenstions will be + assumed to be emojis and stored in the new `pack.json` file. + """ def import_from_fs(conn, _params) do case File.ls(@emoji_dir_path) do {:error, _} -> From f6d4acc87181c94fa202ff5673f741ae9cb45b14 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 10 Sep 2019 22:09:20 +0300 Subject: [PATCH 156/272] Fix credo warnings --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index dc676b00f..cbd237519 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -532,7 +532,8 @@ def import_from_fs(conn, _params) do |> Enum.map(&String.trim/1) |> Enum.map(fn line -> case String.split(line, ~r/,\s*/) do - # This matches both strings with and without tags and we don't care about tags here + # This matches both strings with and without tags + # and we don't care about tags here [name, file | _] -> {name, file} @@ -543,8 +544,8 @@ def import_from_fs(conn, _params) do |> Enum.filter(fn x -> not is_nil(x) end) |> Enum.into(%{}) else - # If there's no emoji.txt, assume all files that are of certain extensions from the config - # are emojis and import them all + # If there's no emoji.txt, assume all files + # that are of certain extensions from the config are emojis and import them all Pleroma.Emoji.make_shortcode_to_file_map( dir_path, Pleroma.Config.get!([:emoji, :pack_extensions]) From 163082de6f789044b4fcb0c69f5b4cfd89731903 Mon Sep 17 00:00:00 2001 From: vaartis Date: Wed, 11 Sep 2019 09:07:19 +0000 Subject: [PATCH 157/272] Apply suggestion to lib/pleroma/web/emoji_api/emoji_api_controller.ex --- .../web/emoji_api/emoji_api_controller.ex | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index cbd237519..499802fa5 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -104,22 +104,14 @@ defp make_archive(name, pack, pack_dir) do # Having a different pack.json md5 invalidates cache pack_file_md5 = :crypto.hash(:md5, File.read!(Path.join(pack_dir, "pack.json"))) - maybe_cached_pack = Cachex.get!(:emoji_packs_cache, name) + case Cachex.get!(:emoji_packs_cache, name) do + %{pack_file_md5: ^pack_file_md5, pack_data: zip_result} -> + Logger.debug("Using cache for the '#{name}' shared emoji pack") + zip_result - zip_result = - if is_nil(maybe_cached_pack) do + _ -> create_archive_and_cache(name, pack, pack_dir, pack_file_md5) - else - if maybe_cached_pack[:pack_file_md5] == pack_file_md5 do - Logger.debug("Using cache for the '#{name}' shared emoji pack") - - maybe_cached_pack[:pack_data] - else - create_archive_and_cache(name, pack, pack_dir, pack_file_md5) - end - end - - zip_result + end end @doc """ From c049c32270b8f70ae679e739730a3f63cdbd7d95 Mon Sep 17 00:00:00 2001 From: vaartis Date: Wed, 11 Sep 2019 09:12:22 +0000 Subject: [PATCH 158/272] Fixed a typo in create_archive_and_cache --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 499802fa5..51620a3eb 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -94,7 +94,7 @@ defp create_archive_and_cache(name, pack, pack_dir, md5) do ttl: cache_ms ) - Logger.debug("Create an archive for the '#{name}' emoji pack, \ + Logger.debug("Created an archive for the '#{name}' emoji pack, \ keeping it in cache for #{div(cache_ms, 1000)}s") zip_result From f251225caeede08869b472886337afea0cd47d51 Mon Sep 17 00:00:00 2001 From: vaartis Date: Wed, 11 Sep 2019 15:32:54 +0000 Subject: [PATCH 159/272] Apply suggestions to emoji_api_controller.ex --- .../web/emoji_api/emoji_api_controller.ex | 201 +++++++++--------- 1 file changed, 95 insertions(+), 106 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 51620a3eb..0c3da6740 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -153,31 +153,32 @@ def download_shared(conn, %{"name" => name}) do from that instance, otherwise it will be downloaded from the fallback source, if there is one. """ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do - list_uri = "#{address}/api/pleroma/emoji/packs/list" - - list = Tesla.get!(list_uri).body |> Jason.decode!() - full_pack = list[name] + full_pack = + "#{address}/api/pleroma/emoji/packs/list" + |> Tesla.get!() + |> Map.get(:body) + |> Jason.decode!() + |> Map.get(name) pfiles = full_pack["files"] - pack = full_pack["pack"] pack_info_res = - cond do - pack["share-files"] && pack["can-download"] -> + case full_pack["pack"] do + %{"share-files" => true, "can-download" => true, "download-sha256" => sha} -> {:ok, %{ - sha: pack["download-sha256"], + sha: sha, uri: "#{address}/api/pleroma/emoji/packs/download_shared/#{name}" }} - pack["fallback-src"] -> + %{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) -> {:ok, %{ - sha: pack["fallback-src-sha256"], - uri: pack["fallback-src"], + sha: sha, + uri: src, fallback: true }} - true -> + _ -> {:error, "The pack was not set as shared and there is no fallback src to download from"} end @@ -194,9 +195,9 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = File.mkdir_p!(pack_dir) # Fallback cannot contain a pack.json file - files = - unless(pinfo[:fallback], do: ['pack.json'], else: []) ++ - (pfiles |> Enum.map(fn {_, path} -> to_charlist(path) end)) + files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end) + # Fallback cannot contain a pack.json file + files = if pinfo[:fallback], do: files, else: ['pack.json'] ++ files {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) @@ -226,7 +227,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = def create(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) - unless File.exists?(pack_dir) do + if not File.exists?(pack_dir) do File.mkdir_p!(pack_dir) pack_file_p = Path.join(pack_dir, "pack.json") @@ -265,8 +266,7 @@ def delete(conn, %{"name" => name}) do `new_data` is the new metadata for the pack, that will replace the old metadata. """ def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do - pack_dir = Path.join(@emoji_dir_path, name) - pack_file_p = Path.join(pack_dir, "pack.json") + pack_file_p = Path.join([@emoji_dir_path, name, "pack.json"]) full_pack = Jason.decode!(File.read!(pack_file_p)) @@ -275,47 +275,42 @@ def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do not is_nil(new_data["fallback-src"]) and new_data["fallback-src"] != full_pack["pack"]["fallback-src"] - new_data = - if should_update_fb_sha do - pack_arch = Tesla.get!(new_data["fallback-src"]).body + with {_, true} <- {:should_update?, should_update_fb_sha}, + %{body: pack_arch} <- Tesla.get!(new_data["fallback-src"]), + {:ok, flist} <- :zip.unzip(pack_arch, [:memory]), + {_, true} <- {:has_all_files?, has_all_files?(full_pack, flist)} do + fallback_sha = :crypto.hash(:sha256, pack_arch) |> Base.encode16() - {:ok, flist} = :zip.unzip(pack_arch, [:memory]) + new_data = Map.put(new_data, "fallback-src-sha256", fallback_sha) + update_metadata_and_send(conn, full_pack, new_data, pack_file_p) + else + {:should_update?, _} -> + update_metadata_and_send(conn, full_pack, new_data, pack_file_p) - # Check if all files from the pack.json are in the archive - has_all_files = - Enum.all?(full_pack["files"], fn {_, from_manifest} -> - Enum.find(flist, fn {from_archive, _} -> - to_string(from_archive) == from_manifest - end) - end) - - unless has_all_files do - {:error, - conn - |> put_status(:bad_request) - |> text("The fallback archive does not have all files specified in pack.json")} - else - fallback_sha = :crypto.hash(:sha256, pack_arch) |> Base.encode16() - - {:ok, new_data |> Map.put("fallback-src-sha256", fallback_sha)} - end - else - {:ok, new_data} - end - - case new_data do - {:ok, new_data} -> - full_pack = Map.put(full_pack, "pack", new_data) - File.write!(pack_file_p, Jason.encode!(full_pack, pretty: true)) - - # Send new data back with fallback sha filled - conn |> json(new_data) - - {:error, e} -> - e + {:has_all_files?, _} -> + conn + |> put_status(:bad_request) + |> text("The fallback archive does not have all files specified in pack.json") end end + # Check if all files from the pack.json are in the archive + defp has_all_files?(%{"files" => files}, flist) do + Enum.all?(files, fn {_, from_manifest} -> + Enum.find(flist, fn {from_archive, _} -> + to_string(from_archive) == from_manifest + end) + end) + end + + defp update_metadata_and_send(conn, full_pack, new_data, pack_file_p) do + full_pack = Map.put(full_pack, "pack", new_data) + File.write!(pack_file_p, Jason.encode!(full_pack, pretty: true)) + + # Send new data back with fallback sha filled + json(conn, new_data) + end + @doc """ Updates a file in a pack. @@ -492,69 +487,63 @@ def update_file( assumed to be emojis and stored in the new `pack.json` file. """ def import_from_fs(conn, _params) do - case File.ls(@emoji_dir_path) do + with {:ok, results} <- File.ls(@emoji_dir_path) do + imported_pack_names = + results + |> Enum.filter(fn file -> + dir_path = Path.join(@emoji_dir_path, file) + # Find the directories that do NOT have pack.json + File.dir?(dir_path) and not File.exists?(Path.join(dir_path, "pack.json")) + end) + |> Enum.map(&write_pack_json_contents/1) + + json(conn, imported_pack_names) + else {:error, _} -> conn |> put_status(:internal_server_error) |> text("Error accessing emoji pack directory") + end + end - {:ok, results} -> - imported_pack_names = - results - |> Enum.filter(fn file -> - dir_path = Path.join(@emoji_dir_path, file) - # Find the directories that do NOT have pack.json - File.dir?(dir_path) and not File.exists?(Path.join(dir_path, "pack.json")) - end) - |> Enum.map(fn dir -> - dir_path = Path.join(@emoji_dir_path, dir) - emoji_txt_path = Path.join(dir_path, "emoji.txt") + defp write_pack_json_contents(dir) do + dir_path = Path.join(@emoji_dir_path, dir) + emoji_txt_path = Path.join(dir_path, "emoji.txt") - files_for_pack = - if File.exists?(emoji_txt_path) do - # There's an emoji.txt file, it's likely from a pack installed by the pack manager. - # Make a pack.json file from the contents of that emoji.txt fileh + files_for_pack = files_for_pack(emoji_txt_path, dir_path) + pack_json_contents = Jason.encode!(%{pack: %{}, files: files_for_pack}) - # FIXME: Copy-pasted from Pleroma.Emoji/load_from_file_stream/2 + File.write!(Path.join(dir_path, "pack.json"), pack_json_contents) - # Create a map of shortcodes to filenames from emoji.txt + dir + end - File.read!(emoji_txt_path) - |> String.split("\n") - |> Enum.map(&String.trim/1) - |> Enum.map(fn line -> - case String.split(line, ~r/,\s*/) do - # This matches both strings with and without tags - # and we don't care about tags here - [name, file | _] -> - {name, file} + defp files_for_pack(emoji_txt_path, dir_path) do + if File.exists?(emoji_txt_path) do + # There's an emoji.txt file, it's likely from a pack installed by the pack manager. + # Make a pack.json file from the contents of that emoji.txt fileh - _ -> - nil - end - end) - |> Enum.filter(fn x -> not is_nil(x) end) - |> Enum.into(%{}) - else - # If there's no emoji.txt, assume all files - # that are of certain extensions from the config are emojis and import them all - Pleroma.Emoji.make_shortcode_to_file_map( - dir_path, - Pleroma.Config.get!([:emoji, :pack_extensions]) - ) - end + # FIXME: Copy-pasted from Pleroma.Emoji/load_from_file_stream/2 - pack_json_contents = Jason.encode!(%{pack: %{}, files: files_for_pack}) - - File.write!( - Path.join(dir_path, "pack.json"), - pack_json_contents - ) - - dir - end) - - conn |> json(imported_pack_names) + # Create a map of shortcodes to filenames from emoji.txt + File.read!(emoji_txt_path) + |> String.split("\n") + |> Enum.map(&String.trim/1) + |> Enum.map(fn line -> + case String.split(line, ~r/,\s*/) do + # This matches both strings with and without tags + # and we don't care about tags here + [name, file | _] -> {name, file} + _ -> nil + end + end) + |> Enum.filter(fn x -> not is_nil(x) end) + |> Enum.into(%{}) + else + # If there's no emoji.txt, assume all files + # that are of certain extensions from the config are emojis and import them all + pack_extensions = Pleroma.Config.get!([:emoji, :pack_extensions]) + Pleroma.Emoji.make_shortcode_to_file_map(dir_path, pack_extensions) end end end From b8a214b0ab264a64ca287e40e99acd401810ef58 Mon Sep 17 00:00:00 2001 From: vaartis Date: Wed, 11 Sep 2019 15:48:51 +0000 Subject: [PATCH 160/272] Split list_packs --- .../web/emoji_api/emoji_api_controller.ex | 75 ++++++++++--------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 0c3da6740..22619f4d7 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -23,47 +23,49 @@ def reload(conn, _params) do a map of "pack directory name" to pack.json contents. """ def list_packs(conn, _params) do - pack_infos = - case File.ls(@emoji_dir_path) do - {:error, _} -> - %{} + with {:ok, results} <- File.ls(@emoji_dir_path) do + pack_infos = + results + |> Enum.filter(&has_pack_json?/1) + |> Enum.map(&load_pack/1) + # Check if all the files are in place and can be sent + |> Enum.map(&validate_pack/1) + # Transform into a map of pack-name => pack-data + |> Enum.into(%{}) - {:ok, results} -> - results - |> Enum.filter(fn file -> - dir_path = Path.join(@emoji_dir_path, file) - # Filter to only use the pack.json packs - File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.json")) - end) - |> Enum.map(fn pack_name -> - pack_path = Path.join(@emoji_dir_path, pack_name) - pack_file = Path.join(pack_path, "pack.json") + json(conn, pack_infos) + end + end - {pack_name, Jason.decode!(File.read!(pack_file))} - end) - # Transform into a map of pack-name => pack-data - # Check if all the files are in place and can be sent - |> Enum.map(fn {name, pack} -> - pack_path = Path.join(@emoji_dir_path, name) + defp has_pack_json?(file) do + dir_path = Path.join(@emoji_dir_path, file) + # Filter to only use the pack.json packs + File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.json")) + end - if can_download?(pack, pack_path) do - archive_for_sha = make_archive(name, pack, pack_path) - archive_sha = :crypto.hash(:sha256, archive_for_sha) |> Base.encode16() + defp load_pack(pack_name) do + pack_path = Path.join(@emoji_dir_path, pack_name) + pack_file = Path.join(pack_path, "pack.json") - {name, - pack - |> put_in(["pack", "can-download"], true) - |> put_in(["pack", "download-sha256"], archive_sha)} - else - {name, - pack - |> put_in(["pack", "can-download"], false)} - end - end) - |> Enum.into(%{}) - end + {pack_name, Jason.decode!(File.read!(pack_file))} + end - conn |> json(pack_infos) + defp validate_pack({name, pack}) do + pack_path = Path.join(@emoji_dir_path, name) + + if can_download?(pack, pack_path) do + archive_for_sha = make_archive(name, pack, pack_path) + archive_sha = :crypto.hash(:sha256, archive_for_sha) |> Base.encode16() + + pack = + pack + |> put_in(["pack", "can-download"], true) + |> put_in(["pack", "download-sha256"], archive_sha) + + {name, pack} + else + {name, put_in(pack, ["pack", "can-download"], false)} + end end defp can_download?(pack, pack_path) do @@ -159,6 +161,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = |> Map.get(:body) |> Jason.decode!() |> Map.get(name) + pfiles = full_pack["files"] pack_info_res = From 8790365fef9d5f76b7ac1c94933e2ee218e76285 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 18:52:21 +0300 Subject: [PATCH 161/272] Remove unused variable --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 22619f4d7..8ef6ae71f 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -162,8 +162,6 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = |> Jason.decode!() |> Map.get(name) - pfiles = full_pack["files"] - pack_info_res = case full_pack["pack"] do %{"share-files" => true, "can-download" => true, "download-sha256" => sha} -> From 8f509e6d1ee8955fc430d1f4ed7929ba0d91177c Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 18:59:31 +0300 Subject: [PATCH 162/272] Use with w/ pack_info_res --- .../web/emoji_api/emoji_api_controller.ex | 52 ++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 8ef6ae71f..9e0ff0b28 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -183,42 +183,36 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = {:error, "The pack was not set as shared and there is no fallback src to download from"} end - case pack_info_res do - {:ok, %{sha: sha, uri: uri} = pinfo} -> - sha = Base.decode16!(sha) - emoji_archive = Tesla.get!(uri).body + with {:ok, %{sha: sha, uri: uri} = pinfo} <- pack_info_res, + %{body: emoji_archive} <- Tesla.get!(uri), + {_, true} <- {:sha, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do + local_name = data["as"] || name + pack_dir = Path.join(@emoji_dir_path, local_name) + File.mkdir_p!(pack_dir) - got_sha = :crypto.hash(:sha256, emoji_archive) + files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end) + # Fallback cannot contain a pack.json file + files = if pinfo[:fallback], do: files, else: ['pack.json'] ++ files - if got_sha == sha do - local_name = data["as"] || name - pack_dir = Path.join(@emoji_dir_path, local_name) - File.mkdir_p!(pack_dir) + {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) - # Fallback cannot contain a pack.json file - files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end) - # Fallback cannot contain a pack.json file - files = if pinfo[:fallback], do: files, else: ['pack.json'] ++ files + # Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256 + # in it to depend on itself + if pinfo[:fallback] do + pack_file_path = Path.join(pack_dir, "pack.json") - {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) - - # Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256 - # in it to depend on itself - if pinfo[:fallback] do - pack_file_path = Path.join(pack_dir, "pack.json") - - File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true)) - end - - conn |> text("ok") - else - conn - |> put_status(:internal_server_error) - |> text("SHA256 for the pack doesn't match the one sent by the server") - end + File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true)) + end + text(conn, "ok") + else {:error, e} -> conn |> put_status(:internal_server_error) |> text(e) + + {:sha, _} -> + conn + |> put_status(:internal_server_error) + |> text("SHA256 for the pack doesn't match the one sent by the server") end end From cb125ffaf7f744e60fc134ef6b7b847d3838922a Mon Sep 17 00:00:00 2001 From: vaartis Date: Wed, 11 Sep 2019 16:00:48 +0000 Subject: [PATCH 163/272] Apply suggestion to lib/pleroma/web/emoji_api/emoji_api_controller.ex --- .../web/emoji_api/emoji_api_controller.ex | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 9e0ff0b28..28eaf5ae3 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -124,26 +124,22 @@ def download_shared(conn, %{"name" => name}) do pack_dir = Path.join(@emoji_dir_path, name) pack_file = Path.join(pack_dir, "pack.json") - if File.exists?(pack_file) do - pack = Jason.decode!(File.read!(pack_file)) - - if can_download?(pack, pack_dir) do - zip_result = make_archive(name, pack, pack_dir) - - conn - |> send_download({:binary, zip_result}, filename: "#{name}.zip") - else - {:error, - conn - |> put_status(:forbidden) - |> text("Pack #{name} cannot be downloaded from this instance, either pack sharing\ - was disabled for this pack or some files are missing")} - end + with {_, true} <- {:exists?, File.exists?(pack_file)}, + pack = Jason.decode!(File.read!(pack_file)), + {_, true} <- {:can_download?, can_download?(pack, pack_dir)} do + zip_result = make_archive(name, pack, pack_dir) + send_download(conn, {:binary, zip_result}, filename: "#{name}.zip") else - {:error, - conn - |> put_status(:not_found) - |> text("Pack #{name} does not exist")} + {:can_download?, _} -> + conn + |> put_status(:forbidden) + |> text("Pack #{name} cannot be downloaded from this instance, either pack sharing\ + was disabled for this pack or some files are missing") + + {:exists?, _} -> + conn + |> put_status(:not_found) + |> text("Pack #{name} does not exist") end end From f24731788ef9dcbeb29c9dc5db9270a5787caff6 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 19:01:21 +0300 Subject: [PATCH 164/272] Move emoji pack list from /list to / --- lib/pleroma/web/router.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 1252048f0..17f7406fd 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -229,7 +229,7 @@ defmodule Pleroma.Web.Router do scope "/packs" do # Pack info / downloading - get("/list", EmojiAPIController, :list_packs) + get("/", EmojiAPIController, :list_packs) get("/download_shared/:name", EmojiAPIController, :download_shared) end end From 7c784128fd8016e133c59e9c5076fa2d77a9bdee Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 19:39:47 +0300 Subject: [PATCH 165/272] Change emoji api responses to JSON --- .../web/emoji_api/emoji_api_controller.ex | 316 ++++++++++-------- test/web/emoji_api_controller_test.exs | 36 +- 2 files changed, 186 insertions(+), 166 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 28eaf5ae3..1c5b7c687 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.EmojiAPI.EmojiAPIController do def reload(conn, _params) do Pleroma.Emoji.reload() - conn |> text("ok") + conn |> json("ok") end @emoji_dir_path Path.join( @@ -133,13 +133,15 @@ def download_shared(conn, %{"name" => name}) do {:can_download?, _} -> conn |> put_status(:forbidden) - |> text("Pack #{name} cannot be downloaded from this instance, either pack sharing\ - was disabled for this pack or some files are missing") + |> json(%{ + error: "Pack #{name} cannot be downloaded from this instance, either pack sharing\ + was disabled for this pack or some files are missing" + }) {:exists?, _} -> conn |> put_status(:not_found) - |> text("Pack #{name} does not exist") + |> json(%{error: "Pack #{name} does not exist"}) end end @@ -200,15 +202,15 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true)) end - text(conn, "ok") + json(conn, "ok") else {:error, e} -> - conn |> put_status(:internal_server_error) |> text(e) + conn |> put_status(:internal_server_error) |> json(%{error: e}) {:sha, _} -> conn |> put_status(:internal_server_error) - |> text("SHA256 for the pack doesn't match the one sent by the server") + |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) end end @@ -228,11 +230,11 @@ def create(conn, %{"name" => name}) do Jason.encode!(%{pack: %{}, files: %{}}) ) - conn |> text("ok") + conn |> json("ok") else conn |> put_status(:conflict) - |> text("A pack named \"#{name}\" already exists") + |> json(%{error: "A pack named \"#{name}\" already exists"}) end end @@ -244,10 +246,12 @@ def delete(conn, %{"name" => name}) do case File.rm_rf(pack_dir) do {:ok, _} -> - conn |> text("ok") + conn |> json("ok") {:error, _} -> - conn |> put_status(:internal_server_error) |> text("Couldn't delete the pack #{name}") + conn + |> put_status(:internal_server_error) + |> json(%{error: "Couldn't delete the pack #{name}"}) end end @@ -281,7 +285,7 @@ def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do {:has_all_files?, _} -> conn |> put_status(:bad_request) - |> text("The fallback archive does not have all files specified in pack.json") + |> json(%{error: "The fallback archive does not have all files specified in pack.json"}) end end @@ -302,6 +306,25 @@ defp update_metadata_and_send(conn, full_pack, new_data, pack_file_p) do json(conn, new_data) end + defp get_filename(%{"filename" => filename}), do: filename + + defp get_filename(%{"file" => file}) do + case file do + %Plug.Upload{filename: filename} -> filename + url when is_binary(url) -> Path.basename(url) + end + end + + defp empty?(str), do: String.trim(str) == "" + + defp update_file_and_send(conn, updated_full_pack, pack_file_p) do + # Write the emoji pack file + File.write!(pack_file_p, Jason.encode!(updated_full_pack, pretty: true)) + + # Return the modified file list + json(conn, updated_full_pack["files"]) + end + @doc """ Updates a file in a pack. @@ -316,157 +339,154 @@ defp update_metadata_and_send(conn, full_pack, new_data, pack_file_p) do (from the current filename to `new_filename`) - `remove` removes the emoji named `shortcode` and it's associated file """ + + # Add def update_file( conn, - %{"pack_name" => pack_name, "action" => action, "shortcode" => shortcode} = params + %{"pack_name" => pack_name, "action" => "add", "shortcode" => shortcode} = params ) do pack_dir = Path.join(@emoji_dir_path, pack_name) pack_file_p = Path.join(pack_dir, "pack.json") full_pack = Jason.decode!(File.read!(pack_file_p)) - res = - case action do - "add" -> - unless Map.has_key?(full_pack["files"], shortcode) do - filename = - if Map.has_key?(params, "filename") do - params["filename"] - else - case params["file"] do - %Plug.Upload{filename: filename} -> filename - url when is_binary(url) -> Path.basename(url) - end - end + with {_, false} <- {:has_shortcode, Map.has_key?(full_pack["files"], shortcode)}, + filename <- get_filename(params), + false <- empty?(shortcode), + false <- empty?(filename) do + file_path = Path.join(pack_dir, filename) - unless String.trim(shortcode) |> String.length() == 0 or - String.trim(filename) |> String.length() == 0 do - file_path = Path.join(pack_dir, filename) - - # If the name contains directories, create them - if String.contains?(file_path, "/") do - File.mkdir_p!(Path.dirname(file_path)) - end - - case params["file"] do - %Plug.Upload{path: upload_path} -> - # Copy the uploaded file from the temporary directory - File.copy!(upload_path, file_path) - - url when is_binary(url) -> - # Download and write the file - file_contents = Tesla.get!(url).body - File.write!(file_path, file_contents) - end - - updated_full_pack = put_in(full_pack, ["files", shortcode], filename) - - {:ok, updated_full_pack} - else - {:error, - conn - |> put_status(:bad_request) - |> text("shortcode or filename cannot be empty")} - end - else - {:error, - conn - |> put_status(:conflict) - |> text("An emoji with the \"#{shortcode}\" shortcode already exists")} - end - - "remove" -> - if Map.has_key?(full_pack["files"], shortcode) do - {emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) - - emoji_file_path = Path.join(pack_dir, emoji_file_path) - - # Delete the emoji file - File.rm!(emoji_file_path) - - # If the old directory has no more files, remove it - if String.contains?(emoji_file_path, "/") do - dir = Path.dirname(emoji_file_path) - - if Enum.empty?(File.ls!(dir)) do - File.rmdir!(dir) - end - end - - {:ok, updated_full_pack} - else - {:error, - conn |> put_status(:bad_request) |> text("Emoji \"#{shortcode}\" does not exist")} - end - - "update" -> - if Map.has_key?(full_pack["files"], shortcode) do - with %{"new_shortcode" => new_shortcode, "new_filename" => new_filename} <- params do - unless String.trim(new_shortcode) |> String.length() == 0 or - String.trim(new_filename) |> String.length() == 0 do - # First, remove the old shortcode, saving the old path - {old_emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) - old_emoji_file_path = Path.join(pack_dir, old_emoji_file_path) - new_emoji_file_path = Path.join(pack_dir, new_filename) - - # If the name contains directories, create them - if String.contains?(new_emoji_file_path, "/") do - File.mkdir_p!(Path.dirname(new_emoji_file_path)) - end - - # Move/Rename the old filename to a new filename - # These are probably on the same filesystem, so just rename should work - :ok = File.rename(old_emoji_file_path, new_emoji_file_path) - - # If the old directory has no more files, remove it - if String.contains?(old_emoji_file_path, "/") do - dir = Path.dirname(old_emoji_file_path) - - if Enum.empty?(File.ls!(dir)) do - File.rmdir!(dir) - end - end - - # Then, put in the new shortcode with the new path - updated_full_pack = - put_in(updated_full_pack, ["files", new_shortcode], new_filename) - - {:ok, updated_full_pack} - else - {:error, - conn - |> put_status(:bad_request) - |> text("new_shortcode or new_filename cannot be empty")} - end - else - _ -> - {:error, - conn - |> put_status(:bad_request) - |> text("new_shortcode or new_file were not specified")} - end - else - {:error, - conn |> put_status(:bad_request) |> text("Emoji \"#{shortcode}\" does not exist")} - end - - _ -> - {:error, conn |> put_status(:bad_request) |> text("Unknown action: #{action}")} + # If the name contains directories, create them + if String.contains?(file_path, "/") do + File.mkdir_p!(Path.dirname(file_path)) end - case res do - {:ok, updated_full_pack} -> - # Write the emoji pack file - File.write!(pack_file_p, Jason.encode!(updated_full_pack, pretty: true)) + case params["file"] do + %Plug.Upload{path: upload_path} -> + # Copy the uploaded file from the temporary directory + File.copy!(upload_path, file_path) - # Return the modified file list - conn |> json(updated_full_pack["files"]) + url when is_binary(url) -> + # Download and write the file + file_contents = Tesla.get!(url).body + File.write!(file_path, file_contents) + end - {:error, e} -> - e + updated_full_pack = put_in(full_pack, ["files", shortcode], filename) + update_file_and_send(conn, updated_full_pack, pack_file_p) + else + {:has_shortcode, _} -> + conn + |> put_status(:conflict) + |> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"}) + + true -> + conn + |> put_status(:bad_request) + |> json(%{error: "shortcode or filename cannot be empty"}) end end + # Remove + def update_file(conn, %{ + "pack_name" => pack_name, + "action" => "remove", + "shortcode" => shortcode + }) do + pack_dir = Path.join(@emoji_dir_path, pack_name) + pack_file_p = Path.join(pack_dir, "pack.json") + + full_pack = Jason.decode!(File.read!(pack_file_p)) + + if Map.has_key?(full_pack["files"], shortcode) do + {emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) + + emoji_file_path = Path.join(pack_dir, emoji_file_path) + + # Delete the emoji file + File.rm!(emoji_file_path) + + # If the old directory has no more files, remove it + if String.contains?(emoji_file_path, "/") do + dir = Path.dirname(emoji_file_path) + + if Enum.empty?(File.ls!(dir)) do + File.rmdir!(dir) + end + end + + update_file_and_send(conn, updated_full_pack, pack_file_p) + else + conn + |> put_status(:bad_request) + |> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) + end + end + + # Update + def update_file( + conn, + %{"pack_name" => pack_name, "action" => "update", "shortcode" => shortcode} = params + ) do + pack_dir = Path.join(@emoji_dir_path, pack_name) + pack_file_p = Path.join(pack_dir, "pack.json") + + full_pack = Jason.decode!(File.read!(pack_file_p)) + + with {_, true} <- {:has_shortcode, Map.has_key?(full_pack["files"], shortcode)}, + %{"new_shortcode" => new_shortcode, "new_filename" => new_filename} <- params, + false <- empty?(new_shortcode), + false <- empty?(new_filename) do + # First, remove the old shortcode, saving the old path + {old_emoji_file_path, updated_full_pack} = pop_in(full_pack, ["files", shortcode]) + old_emoji_file_path = Path.join(pack_dir, old_emoji_file_path) + new_emoji_file_path = Path.join(pack_dir, new_filename) + + # If the name contains directories, create them + if String.contains?(new_emoji_file_path, "/") do + File.mkdir_p!(Path.dirname(new_emoji_file_path)) + end + + # Move/Rename the old filename to a new filename + # These are probably on the same filesystem, so just rename should work + :ok = File.rename(old_emoji_file_path, new_emoji_file_path) + + # If the old directory has no more files, remove it + if String.contains?(old_emoji_file_path, "/") do + dir = Path.dirname(old_emoji_file_path) + + if Enum.empty?(File.ls!(dir)) do + File.rmdir!(dir) + end + end + + # Then, put in the new shortcode with the new path + updated_full_pack = put_in(updated_full_pack, ["files", new_shortcode], new_filename) + update_file_and_send(conn, updated_full_pack, pack_file_p) + else + {:has_shortcode, _} -> + conn + |> put_status(:bad_request) + |> json(%{error: "Emoji \"#{shortcode}\" does not exist"}) + + true -> + conn + |> put_status(:bad_request) + |> json(%{error: "new_shortcode or new_filename cannot be empty"}) + + _ -> + conn + |> put_status(:bad_request) + |> json(%{error: "new_shortcode or new_file were not specified"}) + end + end + + def update_file(conn, %{"action" => action}) do + conn + |> put_status(:bad_request) + |> json(%{error: "Unknown action: #{action}"}) + end + @doc """ Imports emoji from the filesystem. @@ -493,7 +513,7 @@ def import_from_fs(conn, _params) do {:error, _} -> conn |> put_status(:internal_server_error) - |> text("Error accessing emoji pack directory") + |> json(%{error: "Error accessing emoji pack directory"}) end end diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 8b2a942ce..7942a7b01 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -101,14 +101,14 @@ test "downloading shared & unshared packs from another instance via download_fro } |> Jason.encode!() ) - |> text_response(200) == "ok" + |> json_response(200) == "ok" assert File.exists?("#{@emoji_dir_path}/test_pack2/pack.json") assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png") assert conn |> delete(emoji_api_path(conn, :delete, "test_pack2")) - |> response(200) == "ok" + |> json_response(200) == "ok" refute File.exists?("#{@emoji_dir_path}/test_pack2") @@ -130,14 +130,14 @@ test "downloading shared & unshared packs from another instance via download_fro } |> Jason.encode!() ) - |> text_response(200) == "ok" + |> json_response(200) == "ok" assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json") assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png") assert conn |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) - |> response(200) == "ok" + |> json_response(200) == "ok" refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2") end @@ -225,15 +225,15 @@ test "when the fallback source doesn't have all the files", ctx do conn = build_conn() - assert conn - |> assign(:user, ctx[:admin]) - |> post( - emoji_api_path(conn, :update_metadata, "test_pack"), - %{ - "new_data" => new_data - } - ) - |> text_response(:bad_request) =~ "does not have all" + assert (conn + |> assign(:user, ctx[:admin]) + |> post( + emoji_api_path(conn, :update_metadata, "test_pack"), + %{ + "new_data" => new_data + } + ) + |> json_response(:bad_request))["error"] =~ "does not have all" end end @@ -267,9 +267,9 @@ test "updating pack files" do conn = conn |> assign(:user, admin) - assert conn - |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name) - |> text_response(:conflict) =~ "already exists" + assert (conn + |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name) + |> json_response(:conflict))["error"] =~ "already exists" assert conn |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name) @@ -350,7 +350,7 @@ test "creating and deleting a pack" do "test_created" ) ) - |> text_response(200) == "ok" + |> json_response(200) == "ok" assert File.exists?("#{@emoji_dir_path}/test_created/pack.json") @@ -361,7 +361,7 @@ test "creating and deleting a pack" do assert conn |> delete(emoji_api_path(conn, :delete, "test_created")) - |> response(200) == "ok" + |> json_response(200) == "ok" refute File.exists?("#{@emoji_dir_path}/test_created/pack.json") end From 3971bf9c5f00d12a0a2048eb3676069d58a9f243 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 21:43:16 +0300 Subject: [PATCH 166/272] Change :sha to :checksum --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 1c5b7c687..0d4a17c61 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -183,7 +183,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = with {:ok, %{sha: sha, uri: uri} = pinfo} <- pack_info_res, %{body: emoji_archive} <- Tesla.get!(uri), - {_, true} <- {:sha, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do + {_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do local_name = data["as"] || name pack_dir = Path.join(@emoji_dir_path, local_name) File.mkdir_p!(pack_dir) @@ -207,7 +207,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = {:error, e} -> conn |> put_status(:internal_server_error) |> json(%{error: e}) - {:sha, _} -> + {:checksum, _} -> conn |> put_status(:internal_server_error) |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) From 6cd651a38be898456c06d8fee7fd15f1b406848c Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 21:50:55 +0300 Subject: [PATCH 167/272] Make the emoji controller api more RESTy --- lib/pleroma/web/router.ex | 10 +++++----- test/web/emoji_api_controller_test.exs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 17f7406fd..bae25c60a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -220,17 +220,17 @@ defmodule Pleroma.Web.Router do post("/import_from_fs", EmojiAPIController, :import_from_fs) - post("/update_file/:pack_name", EmojiAPIController, :update_file) - post("/update_metadata/:pack_name", EmojiAPIController, :update_metadata) - post("/create/:name", EmojiAPIController, :create) - delete("/delete/:name", EmojiAPIController, :delete) + post("/:pack_name/update_file", EmojiAPIController, :update_file) + post("/:pack_name/update_metadata", EmojiAPIController, :update_metadata) + put("/:name", EmojiAPIController, :create) + delete("/:name", EmojiAPIController, :delete) post("/download_from", EmojiAPIController, :download_from) end scope "/packs" do # Pack info / downloading get("/", EmojiAPIController, :list_packs) - get("/download_shared/:name", EmojiAPIController, :download_shared) + get("/:name/download_shared/", EmojiAPIController, :download_shared) end end diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 7942a7b01..e92e92f74 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -343,7 +343,7 @@ test "creating and deleting a pack" do assert conn |> put_req_header("content-type", "application/json") - |> post( + |> put( emoji_api_path( conn, :create, From dd818bdd487149b75295abd351e3dee3e7378dd7 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 22:39:26 +0300 Subject: [PATCH 168/272] Add documentation for the emoji endpoints --- docs/api/pleroma_api.md | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 30fac77da..a7e7fbe25 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -365,3 +365,69 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * Params: * `recipients`: A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though. * Response: JSON, statuses (200 - healthy, 503 unhealthy) + + +## `POST /api/pleroma/emoji/reload` +### Reload the instance's custom emoji +* Method `POST` +* Authentication: required +* Params: None +* Response: JSON, "ok" and 200 status + +## `PUT /api/pleroma/emoji/packs/:name` +### Creates an empty custom emoji pack +* Method `PUT` +* Authentication: required +* Params: None +* Response: JSON, "ok" and 200 status or 409 if the pack with that name already exists + +## `DELETE /api/pleroma/emoji/packs/:name` +### Delete a custom emoji pack +* Method `DELETE` +* Authentication: required +* Params: None +* Response: JSON, "ok" and 200 status or 500 if there was an error deleting the pack + +## `POST /api/pleroma/emoji/packs/:name/update_file` +### Update a file in a custom emoji pack +* Method `POST` +* Authentication: required +* Params: + * if the `action` is `add`, adds an emoji named `shortcode` to the pack `pack_name`, + that means that the emoji file needs to be uploaded with the request + (thus requiring it to be a multipart request) and be named `file`. + There can also be an optional `filename` that will be the new emoji file name + (if it's not there, the name will be taken from the uploaded file). + * if the `action` is `update`, changes emoji shortcode + (from `shortcode` to `new_shortcode` or moves the file (from the current filename to `new_filename`) + * if the `action` is `remove`, removes the emoji named `shortcode` and it's associated file +* Response: JSON, updated "files" section of the pack and 200 status, 409 if the trying to use a shortcode + that is already taken, 400 if there was an error with the shortcode, filename or file (additional info + in the "error" part of the response JSON) + +## `POST /api/pleroma/emoji/packs/:name/update_metadata` +### Updates (replaces) pack metadata +* Method `POST` +* Authentication: required +* Params: + * `new_data`: new metadata to replace the old one +* Response: JSON, updated "metadata" section of the pack and 200 status or 400 if there was a + problem with the new metadata (the error is specified in the "error" part of the response JSON) + +## `POST /api/pleroma/emoji/packs/download_from` +### Requests the instance to download the pack from another instance +* Method `POST` +* Authentication: required +* Params: + * `instance_address`: the address of the instance to download from + * `pack_name`: the pack to download from that instance +* Response: JSON, "ok" and 200 status if the pack was downloaded, or 500 if there were + errors downloading the pack + +## `GET /api/pleroma/emoji/packs/:name/download_shared` +### Requests the instance to download the pack from another instance +* Method `GET` +* Authentication: not requires +* Params: None +* Response: the archive of the pack with a 200 status code, 403 if the pack is not set as shared, + 404 if the pack does not exist From 74fb6d864760ccaa18b9a20d148c590254779454 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 22:43:00 +0300 Subject: [PATCH 169/272] Move EmojiAPIController from EmojiAPI to PleromaAPI --- lib/pleroma/web/emoji_api/emoji_api_controller.ex | 2 +- lib/pleroma/web/router.ex | 2 +- test/web/emoji_api_controller_test.exs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index 0d4a17c61..a83f8af57 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -1,4 +1,4 @@ -defmodule Pleroma.Web.EmojiAPI.EmojiAPIController do +defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do use Pleroma.Web, :controller require Logger diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index bae25c60a..715e4ba68 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -207,7 +207,7 @@ defmodule Pleroma.Web.Router do get("/moderation_log", AdminAPIController, :list_log) end - scope "/api/pleroma/emoji", Pleroma.Web.EmojiAPI do + scope "/api/pleroma/emoji", Pleroma.Web.PleromaAPI do scope [] do pipe_through([:admin_api, :oauth_write]) diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index e92e92f74..38d11cdce 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -1,4 +1,4 @@ -defmodule Pleroma.Web.EmojiAPI.EmojiAPIControllerTest do +defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do use Pleroma.Web.ConnCase import Tesla.Mock From 36f2275dc9f6c58163e4e07f8ace9d75e96033c7 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 11 Sep 2019 22:58:55 +0300 Subject: [PATCH 170/272] A feature for shareable emoji packs, use it in download_from & tests --- .../web/emoji_api/emoji_api_controller.ex | 115 ++++++++++-------- .../web/nodeinfo/nodeinfo_controller.ex | 1 + test/web/emoji_api_controller_test.exs | 22 ++++ 3 files changed, 88 insertions(+), 50 deletions(-) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/emoji_api/emoji_api_controller.ex index a83f8af57..36ca2c804 100644 --- a/lib/pleroma/web/emoji_api/emoji_api_controller.ex +++ b/lib/pleroma/web/emoji_api/emoji_api_controller.ex @@ -153,64 +153,79 @@ def download_shared(conn, %{"name" => name}) do from that instance, otherwise it will be downloaded from the fallback source, if there is one. """ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do - full_pack = - "#{address}/api/pleroma/emoji/packs/list" + shareable_packs_available = + "#{address}/nodeinfo/2.1.json" |> Tesla.get!() |> Map.get(:body) |> Jason.decode!() - |> Map.get(name) + |> Map.get("features") + |> Enum.member?("shareable_emoji_packs") - pack_info_res = - case full_pack["pack"] do - %{"share-files" => true, "can-download" => true, "download-sha256" => sha} -> - {:ok, - %{ - sha: sha, - uri: "#{address}/api/pleroma/emoji/packs/download_shared/#{name}" - }} + if shareable_packs_available do + full_pack = + "#{address}/api/pleroma/emoji/packs/list" + |> Tesla.get!() + |> Map.get(:body) + |> Jason.decode!() + |> Map.get(name) - %{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) -> - {:ok, - %{ - sha: sha, - uri: src, - fallback: true - }} + pack_info_res = + case full_pack["pack"] do + %{"share-files" => true, "can-download" => true, "download-sha256" => sha} -> + {:ok, + %{ + sha: sha, + uri: "#{address}/api/pleroma/emoji/packs/download_shared/#{name}" + }} - _ -> - {:error, "The pack was not set as shared and there is no fallback src to download from"} + %{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) -> + {:ok, + %{ + sha: sha, + uri: src, + fallback: true + }} + + _ -> + {:error, + "The pack was not set as shared and there is no fallback src to download from"} + end + + with {:ok, %{sha: sha, uri: uri} = pinfo} <- pack_info_res, + %{body: emoji_archive} <- Tesla.get!(uri), + {_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do + local_name = data["as"] || name + pack_dir = Path.join(@emoji_dir_path, local_name) + File.mkdir_p!(pack_dir) + + files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end) + # Fallback cannot contain a pack.json file + files = if pinfo[:fallback], do: files, else: ['pack.json'] ++ files + + {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) + + # Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256 + # in it to depend on itself + if pinfo[:fallback] do + pack_file_path = Path.join(pack_dir, "pack.json") + + File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true)) + end + + json(conn, "ok") + else + {:error, e} -> + conn |> put_status(:internal_server_error) |> json(%{error: e}) + + {:checksum, _} -> + conn + |> put_status(:internal_server_error) + |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) end - - with {:ok, %{sha: sha, uri: uri} = pinfo} <- pack_info_res, - %{body: emoji_archive} <- Tesla.get!(uri), - {_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do - local_name = data["as"] || name - pack_dir = Path.join(@emoji_dir_path, local_name) - File.mkdir_p!(pack_dir) - - files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end) - # Fallback cannot contain a pack.json file - files = if pinfo[:fallback], do: files, else: ['pack.json'] ++ files - - {:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files) - - # Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256 - # in it to depend on itself - if pinfo[:fallback] do - pack_file_path = Path.join(pack_dir, "pack.json") - - File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true)) - end - - json(conn, "ok") else - {:error, e} -> - conn |> put_status(:internal_server_error) |> json(%{error: e}) - - {:checksum, _} -> - conn - |> put_status(:internal_server_error) - |> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"}) + conn + |> put_status(:internal_server_error) + |> json(%{error: "The requested instance does not support sharing emoji packs"}) end end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index ee14cfd6b..192984242 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -57,6 +57,7 @@ def raw_nodeinfo do "mastodon_api_streaming", "polls", "pleroma_explicit_addressing", + "shareable_emoji_packs", if Config.get([:media_proxy, :enabled]) do "media_proxy" end, diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 38d11cdce..1af4d3720 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -54,6 +54,12 @@ test "downloading shared & unshared packs from another instance via download_fro end) mock(fn + %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> + json(%{features: []}) + + %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> + json(%{features: ["shareable_emoji_packs"]}) + %{ method: :get, url: "https://example.com/api/pleroma/emoji/packs/list" @@ -87,6 +93,22 @@ test "downloading shared & unshared packs from another instance via download_fro conn = build_conn() |> assign(:user, admin) + assert (conn + |> put_req_header("content-type", "application/json") + |> post( + emoji_api_path( + conn, + :download_from + ), + %{ + instance_address: "https://old-instance", + pack_name: "test_pack", + as: "test_pack2" + } + |> Jason.encode!() + ) + |> json_response(500))["error"] =~ "does not support" + assert conn |> put_req_header("content-type", "application/json") |> post( From 7680aec17d6690ccf7383354572456c2118a8750 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 12 Sep 2019 00:00:28 +0300 Subject: [PATCH 171/272] Move emoji api to pleroma api dir --- .../web/{emoji_api => pleroma_api}/emoji_api_controller.ex | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/pleroma/web/{emoji_api => pleroma_api}/emoji_api_controller.ex (100%) diff --git a/lib/pleroma/web/emoji_api/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/emoji_api_controller.ex similarity index 100% rename from lib/pleroma/web/emoji_api/emoji_api_controller.ex rename to lib/pleroma/web/pleroma_api/emoji_api_controller.ex From d51e5e447ee944e77646b15a7aabc0214e99c351 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 12 Sep 2019 20:38:57 +0300 Subject: [PATCH 172/272] Move emoji reloading to admin api --- docs/api/admin_api.md | 7 +++++++ docs/api/pleroma_api.md | 8 -------- lib/pleroma/web/admin_api/admin_api_controller.ex | 6 ++++++ lib/pleroma/web/pleroma_api/emoji_api_controller.ex | 6 ------ lib/pleroma/web/router.ex | 8 ++------ 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 7637fa0d4..0377ea655 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -733,3 +733,10 @@ Compile time settings (need instance reboot): } ] ``` + +## `POST /api/pleroma/admin/reload_emoji` +### Reload the instance's custom emoji +* Method `POST` +* Authentication: required +* Params: None +* Response: JSON, "ok" and 200 status diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index a7e7fbe25..05a4e6fcc 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -366,14 +366,6 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * `recipients`: A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though. * Response: JSON, statuses (200 - healthy, 503 unhealthy) - -## `POST /api/pleroma/emoji/reload` -### Reload the instance's custom emoji -* Method `POST` -* Authentication: required -* Params: None -* Response: JSON, "ok" and 200 status - ## `PUT /api/pleroma/emoji/packs/:name` ### Creates an empty custom emoji pack * Method `PUT` diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 8a8091daa..4d4e862dd 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -599,6 +599,12 @@ def config_update(conn, %{"configs" => configs}) do |> render("index.json", %{configs: updated}) end + def reload_emoji(conn, _params) do + Pleroma.Emoji.reload() + + conn |> json("ok") + end + def errors(conn, {:error, :not_found}) do conn |> put_status(:not_found) diff --git a/lib/pleroma/web/pleroma_api/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/emoji_api_controller.ex index 36ca2c804..bc1639095 100644 --- a/lib/pleroma/web/pleroma_api/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/emoji_api_controller.ex @@ -3,12 +3,6 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do require Logger - def reload(conn, _params) do - Pleroma.Emoji.reload() - - conn |> json("ok") - end - @emoji_dir_path Path.join( Pleroma.Config.get!([:instance, :static_dir]), "emoji" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 715e4ba68..71ef382c5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -205,15 +205,11 @@ defmodule Pleroma.Web.Router do get("/config/migrate_from_db", AdminAPIController, :migrate_from_db) get("/moderation_log", AdminAPIController, :list_log) + + post("/reload_emoji", AdminAPIController, :reload_emoji) end scope "/api/pleroma/emoji", Pleroma.Web.PleromaAPI do - scope [] do - pipe_through([:admin_api, :oauth_write]) - - post("/reload", EmojiAPIController, :reload) - end - scope "/packs" do # Modifying packs pipe_through([:admin_api, :oauth_write]) From 8aed05ac1518a10fb30532429984e02a05180ec3 Mon Sep 17 00:00:00 2001 From: vaartis Date: Fri, 13 Sep 2019 12:32:23 +0000 Subject: [PATCH 173/272] Apply suggestion to docs/api/pleroma_api.md --- docs/api/pleroma_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 05a4e6fcc..e76bf0caf 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -417,7 +417,7 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa errors downloading the pack ## `GET /api/pleroma/emoji/packs/:name/download_shared` -### Requests the instance to download the pack from another instance +### Requests a local pack from the instance * Method `GET` * Authentication: not requires * Params: None From 43022c347f9001d9cb8de976dd521a1e5f1c1318 Mon Sep 17 00:00:00 2001 From: vaartis Date: Fri, 13 Sep 2019 12:32:40 +0000 Subject: [PATCH 174/272] Apply suggestion to docs/api/pleroma_api.md --- docs/api/pleroma_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index e76bf0caf..faf6e3acd 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -419,7 +419,7 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa ## `GET /api/pleroma/emoji/packs/:name/download_shared` ### Requests a local pack from the instance * Method `GET` -* Authentication: not requires +* Authentication: not required * Params: None * Response: the archive of the pack with a 200 status code, 403 if the pack is not set as shared, 404 if the pack does not exist From 86795d5ac2604e08654b872927678d3e05a68e85 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Fri, 13 Sep 2019 21:00:28 +0300 Subject: [PATCH 175/272] Document emoji pack listing in the api docs --- docs/api/pleroma_api.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index faf6e3acd..a469ddfbf 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -366,6 +366,13 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * `recipients`: A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though. * Response: JSON, statuses (200 - healthy, 503 unhealthy) +## `GET /api/pleroma/emoji/packs` +### Lists the custom emoji packs on the server +* Method `GET` +* Authentication: not required +* Params: None +* Response: JSON, "ok" and 200 status and the JSON hashmap of "pack name" to "pack contents" + ## `PUT /api/pleroma/emoji/packs/:name` ### Creates an empty custom emoji pack * Method `PUT` From a1325d5fd9b540017cbffbb73db85ee9fa9f12d0 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 18 Sep 2019 18:09:57 +0300 Subject: [PATCH 176/272] Change path from nodeinfo to metadata->features --- lib/pleroma/web/pleroma_api/emoji_api_controller.ex | 2 +- test/web/emoji_api_controller_test.exs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/emoji_api_controller.ex index bc1639095..391c317e7 100644 --- a/lib/pleroma/web/pleroma_api/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/emoji_api_controller.ex @@ -152,7 +152,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = |> Tesla.get!() |> Map.get(:body) |> Jason.decode!() - |> Map.get("features") + |> get_in(["metadata", "features"]) |> Enum.member?("shareable_emoji_packs") if shareable_packs_available do diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 1af4d3720..297dc092f 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -55,10 +55,10 @@ test "downloading shared & unshared packs from another instance via download_fro mock(fn %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> - json(%{features: []}) + json(%{metadata: %{features: []}}) %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> - json(%{features: ["shareable_emoji_packs"]}) + json(%{metadata: %{features: ["shareable_emoji_packs"]}}) %{ method: :get, From b585134c9092b49e7b5c24e04d6d6315d45dd0a2 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 18 Sep 2019 19:48:25 +0300 Subject: [PATCH 177/272] Get the nodeinfo address from the well-known --- lib/pleroma/web/pleroma_api/emoji_api_controller.ex | 8 +++++++- test/web/emoji_api_controller_test.exs | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/pleroma_api/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/emoji_api_controller.ex index 391c317e7..6beca426a 100644 --- a/lib/pleroma/web/pleroma_api/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/emoji_api_controller.ex @@ -148,7 +148,13 @@ def download_shared(conn, %{"name" => name}) do """ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do shareable_packs_available = - "#{address}/nodeinfo/2.1.json" + "#{address}/.well-known/nodeinfo" + |> Tesla.get!() + |> Map.get(:body) + |> Jason.decode!() + |> List.last() + |> Map.get("href") + # Get the actual nodeinfo address and fetch it |> Tesla.get!() |> Map.get(:body) |> Jason.decode!() diff --git a/test/web/emoji_api_controller_test.exs b/test/web/emoji_api_controller_test.exs index 297dc092f..c5a553692 100644 --- a/test/web/emoji_api_controller_test.exs +++ b/test/web/emoji_api_controller_test.exs @@ -54,9 +54,15 @@ test "downloading shared & unshared packs from another instance via download_fro end) mock(fn + %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} -> + json([%{href: "https://old-instance/nodeinfo/2.1.json"}]) + %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> json(%{metadata: %{features: []}}) + %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> + json([%{href: "https://example.com/nodeinfo/2.1.json"}]) + %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> json(%{metadata: %{features: ["shareable_emoji_packs"]}}) From c3856bed0c4c177c3e6716d06d615a928d95f69c Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 18 Sep 2019 23:17:15 +0200 Subject: [PATCH 178/272] docs/clients.md: Update source code urls --- docs/clients.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/clients.md b/docs/clients.md index 9029361f8..6c6180f7a 100644 --- a/docs/clients.md +++ b/docs/clients.md @@ -39,7 +39,7 @@ Feel free to contact us to be added to this list! ### Nekonium - Homepage: [F-Droid Repository](https://repo.gdgd.jp.net/), [Google Play](https://play.google.com/store/apps/details?id=com.apps.nekonium), [Amazon](https://www.amazon.co.jp/dp/B076FXPRBC/) -- Source: +- Source: - Contact: [@lin@pleroma.gdgd.jp.net](https://pleroma.gdgd.jp.net/users/lin) - Platforms: Android - Features: Streaming Ready @@ -67,7 +67,7 @@ Feel free to contact us to be added to this list! ## Alternative Web Interfaces ### Brutaldon - Homepage: -- Source Code: +- Source Code: - Contact: [@gcupc@glitch.social](https://glitch.social/users/gcupc) - Features: No Streaming From 447514dfa2759e3415399412e82bf772ff119e04 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 18 Sep 2019 23:20:54 +0200 Subject: [PATCH 179/272] Bump copyright years of files changed in 2019 Done via the following command: git diff 1e6c102bfcfe0e4835a48f2483f2376f9bf86a20 --stat --name-only | cat - | xargs sed -i 's/2017-2018 Pleroma Authors/2017-2019 Pleroma Authors/' --- lib/mix/pleroma.ex | 2 +- lib/mix/tasks/pleroma/database.ex | 2 +- lib/mix/tasks/pleroma/ecto/ecto.ex | 2 +- lib/mix/tasks/pleroma/ecto/migrate.ex | 2 +- lib/mix/tasks/pleroma/ecto/rollback.ex | 2 +- lib/mix/tasks/pleroma/emoji.ex | 2 +- lib/mix/tasks/pleroma/instance.ex | 2 +- lib/mix/tasks/pleroma/relay.ex | 2 +- lib/mix/tasks/pleroma/uploads.ex | 2 +- lib/mix/tasks/pleroma/user.ex | 2 +- lib/pleroma/activity/queries.ex | 2 +- lib/pleroma/user/query.ex | 2 +- lib/pleroma/web/oauth/token/clean_worker.ex | 2 +- lib/pleroma/web/oauth/token/query.ex | 2 +- test/activity_test.exs | 2 +- test/captcha_test.exs | 2 +- test/config_test.exs | 2 +- test/daemons/activity_expiration_daemon_test.exs | 2 +- test/daemons/scheduled_activity_daemon_test.exs | 2 +- test/emails/admin_email_test.exs | 2 +- test/emails/mailer_test.exs | 2 +- test/emails/user_email_test.exs | 2 +- test/formatter_test.exs | 2 +- test/html_test.exs | 2 +- test/integration/mastodon_websocket_test.exs | 2 +- test/list_test.exs | 2 +- test/notification_test.exs | 2 +- test/object_test.exs | 2 +- test/plugs/authentication_plug_test.exs | 2 +- test/plugs/cache_control_test.exs | 2 +- test/plugs/ensure_public_or_authenticated_plug_test.exs | 2 +- test/plugs/http_security_plug_test.exs | 2 +- test/plugs/http_signature_plug_test.exs | 2 +- test/plugs/instance_static_test.exs | 2 +- test/plugs/legacy_authentication_plug_test.exs | 2 +- test/plugs/mapped_identity_to_signature_plug_test.exs | 2 +- test/plugs/oauth_plug_test.exs | 2 +- test/plugs/oauth_scopes_plug_test.exs | 2 +- test/plugs/set_format_plug_test.exs | 2 +- test/plugs/set_locale_plug_test.exs | 2 +- test/plugs/uploaded_media_plug_test.exs | 2 +- test/scheduled_activity_test.exs | 2 +- test/support/captcha_mock.ex | 2 +- test/support/conn_case.ex | 2 +- test/support/data_case.ex | 2 +- test/support/helpers.ex | 2 +- test/support/http_request_mock.ex | 2 +- test/support/mrf_module_mock.ex | 2 +- test/support/oban_helpers.ex | 2 +- test/support/web_push_http_client_mock.ex | 2 +- test/tasks/ecto/migrate_test.exs | 2 +- test/tasks/relay_test.exs | 2 +- test/tasks/user_test.exs | 2 +- test/test_helper.exs | 2 +- test/upload_test.exs | 2 +- test/user_search_test.exs | 2 +- test/user_test.exs | 2 +- test/web/activity_pub/activity_pub_controller_test.exs | 2 +- test/web/activity_pub/relay_test.exs | 2 +- test/web/activity_pub/transmogrifier/follow_handling_test.exs | 2 +- test/web/activity_pub/transmogrifier_test.exs | 2 +- test/web/admin_api/admin_api_controller_test.exs | 2 +- test/web/admin_api/search_test.exs | 2 +- test/web/common_api/common_api_utils_test.exs | 2 +- test/web/federator_test.exs | 2 +- test/web/instances/instance_test.exs | 2 +- test/web/instances/instances_test.exs | 2 +- test/web/mastodon_api/views/account_view_test.exs | 2 +- test/web/mastodon_api/views/list_view_test.exs | 2 +- test/web/mastodon_api/views/notification_view_test.exs | 2 +- test/web/mastodon_api/views/push_subscription_view_test.exs | 2 +- test/web/mastodon_api/views/scheduled_activity_view_test.exs | 2 +- test/web/mastodon_api/views/status_view_test.exs | 2 +- test/web/media_proxy/media_proxy_controller_test.exs | 2 +- test/web/media_proxy/media_proxy_test.exs | 2 +- test/web/node_info_test.exs | 2 +- test/web/oauth/authorization_test.exs | 2 +- test/web/oauth/oauth_controller_test.exs | 2 +- test/web/oauth/token/utils_test.exs | 2 +- test/web/oauth/token_test.exs | 2 +- test/web/ostatus/activity_representer_test.exs | 2 +- test/web/ostatus/feed_representer_test.exs | 2 +- test/web/ostatus/ostatus_controller_test.exs | 2 +- test/web/ostatus/ostatus_test.exs | 2 +- test/web/plugs/federating_plug_test.exs | 2 +- test/web/push/impl_test.exs | 2 +- test/web/salmon/salmon_test.exs | 2 +- test/web/streamer/streamer_test.exs | 2 +- test/web/twitter_api/twitter_api_test.exs | 2 +- test/web/uploader_controller_test.exs | 2 +- test/web/views/error_view_test.exs | 2 +- test/web/web_finger/web_finger_controller_test.exs | 2 +- test/web/web_finger/web_finger_test.exs | 2 +- test/web/websub/websub_controller_test.exs | 2 +- test/web/websub/websub_test.exs | 2 +- 95 files changed, 95 insertions(+), 95 deletions(-) diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index 1b758ea33..faeb30e1d 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Pleroma do diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index bcc2052d6..890a383df 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.Database do diff --git a/lib/mix/tasks/pleroma/ecto/ecto.ex b/lib/mix/tasks/pleroma/ecto/ecto.ex index b66f63376..36808b93f 100644 --- a/lib/mix/tasks/pleroma/ecto/ecto.ex +++ b/lib/mix/tasks/pleroma/ecto/ecto.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-onl defmodule Mix.Tasks.Pleroma.Ecto do diff --git a/lib/mix/tasks/pleroma/ecto/migrate.ex b/lib/mix/tasks/pleroma/ecto/migrate.ex index 855c977f6..d87b6957d 100644 --- a/lib/mix/tasks/pleroma/ecto/migrate.ex +++ b/lib/mix/tasks/pleroma/ecto/migrate.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-onl defmodule Mix.Tasks.Pleroma.Ecto.Migrate do diff --git a/lib/mix/tasks/pleroma/ecto/rollback.ex b/lib/mix/tasks/pleroma/ecto/rollback.ex index 2ffb0901c..a1af73fa1 100644 --- a/lib/mix/tasks/pleroma/ecto/rollback.ex +++ b/lib/mix/tasks/pleroma/ecto/rollback.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-onl defmodule Mix.Tasks.Pleroma.Ecto.Rollback do diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index c2225af7d..238d8dcd9 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.Emoji do diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index b9b1991c2..1a1634fe9 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.Instance do diff --git a/lib/mix/tasks/pleroma/relay.ex b/lib/mix/tasks/pleroma/relay.ex index a738fae75..200721163 100644 --- a/lib/mix/tasks/pleroma/relay.ex +++ b/lib/mix/tasks/pleroma/relay.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.Relay do diff --git a/lib/mix/tasks/pleroma/uploads.ex b/lib/mix/tasks/pleroma/uploads.ex index be45383ee..95392d81b 100644 --- a/lib/mix/tasks/pleroma/uploads.ex +++ b/lib/mix/tasks/pleroma/uploads.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.Uploads do diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index a3f8bc945..eb0052144 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.User do diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex index 13fa33831..949f010a8 100644 --- a/lib/pleroma/activity/queries.ex +++ b/lib/pleroma/activity/queries.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Activity.Queries do diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index f9bcc9e19..2baf016cf 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User.Query do diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex index eb94bf86f..f639f9c6f 100644 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.Token.CleanWorker do diff --git a/lib/pleroma/web/oauth/token/query.ex b/lib/pleroma/web/oauth/token/query.ex index d92e1f071..9642103e6 100644 --- a/lib/pleroma/web/oauth/token/query.ex +++ b/lib/pleroma/web/oauth/token/query.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.Token.Query do diff --git a/test/activity_test.exs b/test/activity_test.exs index 6512d84ac..95d9341c4 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ActivityTest do diff --git a/test/captcha_test.exs b/test/captcha_test.exs index 7ca9a4607..9f395d6b4 100644 --- a/test/captcha_test.exs +++ b/test/captcha_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.CaptchaTest do diff --git a/test/config_test.exs b/test/config_test.exs index 73f3fcb0a..438fe62ee 100644 --- a/test/config_test.exs +++ b/test/config_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ConfigTest do diff --git a/test/daemons/activity_expiration_daemon_test.exs b/test/daemons/activity_expiration_daemon_test.exs index 31f4a70a6..b51132fb0 100644 --- a/test/daemons/activity_expiration_daemon_test.exs +++ b/test/daemons/activity_expiration_daemon_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ActivityExpirationWorkerTest do diff --git a/test/daemons/scheduled_activity_daemon_test.exs b/test/daemons/scheduled_activity_daemon_test.exs index 32820b2b7..c8e464491 100644 --- a/test/daemons/scheduled_activity_daemon_test.exs +++ b/test/daemons/scheduled_activity_daemon_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ScheduledActivityDaemonTest do diff --git a/test/emails/admin_email_test.exs b/test/emails/admin_email_test.exs index 9e83c73c6..31eac5f12 100644 --- a/test/emails/admin_email_test.exs +++ b/test/emails/admin_email_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emails.AdminEmailTest do diff --git a/test/emails/mailer_test.exs b/test/emails/mailer_test.exs index ae5effb7a..2425c85dd 100644 --- a/test/emails/mailer_test.exs +++ b/test/emails/mailer_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emails.MailerTest do diff --git a/test/emails/user_email_test.exs b/test/emails/user_email_test.exs index 7d8df6abc..963565f7c 100644 --- a/test/emails/user_email_test.exs +++ b/test/emails/user_email_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emails.UserEmailTest do diff --git a/test/formatter_test.exs b/test/formatter_test.exs index bfa673049..c443dfe7c 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.FormatterTest do diff --git a/test/html_test.exs b/test/html_test.exs index b8906c46a..306ad3b3b 100644 --- a/test/html_test.exs +++ b/test/html_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTMLTest do diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index d02a3cc4d..ed7ce8fe0 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Integration.MastodonWebsocketTest do diff --git a/test/list_test.exs b/test/list_test.exs index 8efba75ea..ba79251da 100644 --- a/test/list_test.exs +++ b/test/list_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ListTest do diff --git a/test/notification_test.exs b/test/notification_test.exs index 3d2f9a8fc..54c0f9877 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.NotificationTest do diff --git a/test/object_test.exs b/test/object_test.exs index ba96aeea4..570213a61 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ObjectTest do diff --git a/test/plugs/authentication_plug_test.exs b/test/plugs/authentication_plug_test.exs index f7f8fd9f3..9ae4c506f 100644 --- a/test/plugs/authentication_plug_test.exs +++ b/test/plugs/authentication_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.AuthenticationPlugTest do diff --git a/test/plugs/cache_control_test.exs b/test/plugs/cache_control_test.exs index 45151b289..69ce6cc7d 100644 --- a/test/plugs/cache_control_test.exs +++ b/test/plugs/cache_control_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.CacheControlTest do diff --git a/test/plugs/ensure_public_or_authenticated_plug_test.exs b/test/plugs/ensure_public_or_authenticated_plug_test.exs index d45662a2a..bae95e150 100644 --- a/test/plugs/ensure_public_or_authenticated_plug_test.exs +++ b/test/plugs/ensure_public_or_authenticated_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do diff --git a/test/plugs/http_security_plug_test.exs b/test/plugs/http_security_plug_test.exs index 7a2835e3d..9c1c20541 100644 --- a/test/plugs/http_security_plug_test.exs +++ b/test/plugs/http_security_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do diff --git a/test/plugs/http_signature_plug_test.exs b/test/plugs/http_signature_plug_test.exs index d6fd9ea81..d8ace36da 100644 --- a/test/plugs/http_signature_plug_test.exs +++ b/test/plugs/http_signature_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do diff --git a/test/plugs/instance_static_test.exs b/test/plugs/instance_static_test.exs index 6aabc45a4..9b27246fa 100644 --- a/test/plugs/instance_static_test.exs +++ b/test/plugs/instance_static_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.RuntimeStaticPlugTest do diff --git a/test/plugs/legacy_authentication_plug_test.exs b/test/plugs/legacy_authentication_plug_test.exs index 9804e073b..568ef5abd 100644 --- a/test/plugs/legacy_authentication_plug_test.exs +++ b/test/plugs/legacy_authentication_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do diff --git a/test/plugs/mapped_identity_to_signature_plug_test.exs b/test/plugs/mapped_identity_to_signature_plug_test.exs index bb45d9edf..6b9d3649d 100644 --- a/test/plugs/mapped_identity_to_signature_plug_test.exs +++ b/test/plugs/mapped_identity_to_signature_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlugTest do diff --git a/test/plugs/oauth_plug_test.exs b/test/plugs/oauth_plug_test.exs index 5a2ed11cc..dea11cdb0 100644 --- a/test/plugs/oauth_plug_test.exs +++ b/test/plugs/oauth_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.OAuthPlugTest do diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/plugs/oauth_scopes_plug_test.exs index f328026df..6a13ea811 100644 --- a/test/plugs/oauth_scopes_plug_test.exs +++ b/test/plugs/oauth_scopes_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.OAuthScopesPlugTest do diff --git a/test/plugs/set_format_plug_test.exs b/test/plugs/set_format_plug_test.exs index bb21956bb..27c026fdd 100644 --- a/test/plugs/set_format_plug_test.exs +++ b/test/plugs/set_format_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.SetFormatPlugTest do diff --git a/test/plugs/set_locale_plug_test.exs b/test/plugs/set_locale_plug_test.exs index b6c4c1cea..0aaeedc1e 100644 --- a/test/plugs/set_locale_plug_test.exs +++ b/test/plugs/set_locale_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.SetLocalePlugTest do diff --git a/test/plugs/uploaded_media_plug_test.exs b/test/plugs/uploaded_media_plug_test.exs index 49cf5396a..5ba963139 100644 --- a/test/plugs/uploaded_media_plug_test.exs +++ b/test/plugs/uploaded_media_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.UploadedMediaPlugTest do diff --git a/test/scheduled_activity_test.exs b/test/scheduled_activity_test.exs index edc7cc3f9..dcf12fb49 100644 --- a/test/scheduled_activity_test.exs +++ b/test/scheduled_activity_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ScheduledActivityTest do diff --git a/test/support/captcha_mock.ex b/test/support/captcha_mock.ex index ef4e68bc5..65ca6b3bd 100644 --- a/test/support/captcha_mock.ex +++ b/test/support/captcha_mock.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Captcha.Mock do diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index b39c70677..9897f72ce 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ConnCase do diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 17fa15214..4ffcbac9e 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.DataCase do diff --git a/test/support/helpers.ex b/test/support/helpers.ex index a601b3ec8..ce39dd9d8 100644 --- a/test/support/helpers.ex +++ b/test/support/helpers.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Tests.Helpers do diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 231e7c498..6f9886836 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule HttpRequestMock do diff --git a/test/support/mrf_module_mock.ex b/test/support/mrf_module_mock.ex index 12c7e22bc..632c7ff1d 100644 --- a/test/support/mrf_module_mock.ex +++ b/test/support/mrf_module_mock.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule MRFModuleMock do diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex index 989770926..72792c064 100644 --- a/test/support/oban_helpers.ex +++ b/test/support/oban_helpers.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Tests.ObanHelpers do diff --git a/test/support/web_push_http_client_mock.ex b/test/support/web_push_http_client_mock.ex index d8accd21c..1d6ccff7e 100644 --- a/test/support/web_push_http_client_mock.ex +++ b/test/support/web_push_http_client_mock.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebPushHttpClientMock do diff --git a/test/tasks/ecto/migrate_test.exs b/test/tasks/ecto/migrate_test.exs index 0538a7b40..42f6cbf47 100644 --- a/test/tasks/ecto/migrate_test.exs +++ b/test/tasks/ecto/migrate_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-onl defmodule Mix.Tasks.Pleroma.Ecto.MigrateTest do diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs index 7bde56606..c866608ab 100644 --- a/test/tasks/relay_test.exs +++ b/test/tasks/relay_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.RelayTest do diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs index 2b9453042..cf12d9ed6 100644 --- a/test/tasks/user_test.exs +++ b/test/tasks/user_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.UserTest do diff --git a/test/test_helper.exs b/test/test_helper.exs index a927b2c3d..fb33e0969 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: [] diff --git a/test/upload_test.exs b/test/upload_test.exs index 6721fe82e..0ca5ebced 100644 --- a/test/upload_test.exs +++ b/test/upload_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UploadTest do diff --git a/test/user_search_test.exs b/test/user_search_test.exs index 48ce973ad..f7ab31287 100644 --- a/test/user_search_test.exs +++ b/test/user_search_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserSearchTest do diff --git a/test/user_test.exs b/test/user_test.exs index b09e9311d..39ba69668 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserTest do diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index f83b14452..9e8e420ec 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 7315dce26..0f7556538 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.RelayTest do diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs index fe89f7cb0..99ab573c5 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 6c296eb0d..ebed65b7c 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index c497ea098..41b4364f2 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs index 501a8d007..9df4cd539 100644 --- a/test/web/admin_api/search_test.exs +++ b/test/web/admin_api/search_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.SearchTest do diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index c281dd1f1..230146451 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.CommonAPI.UtilsTest do diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 4096d4690..43a715706 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.FederatorTest do diff --git a/test/web/instances/instance_test.exs b/test/web/instances/instance_test.exs index 0b53bc6cd..e54d708ad 100644 --- a/test/web/instances/instance_test.exs +++ b/test/web/instances/instance_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Instances.InstanceTest do diff --git a/test/web/instances/instances_test.exs b/test/web/instances/instances_test.exs index dea8e2aea..65b03b155 100644 --- a/test/web/instances/instances_test.exs +++ b/test/web/instances/instances_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.InstancesTest do diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 1d8b28339..2ea87c5f0 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.AccountViewTest do diff --git a/test/web/mastodon_api/views/list_view_test.exs b/test/web/mastodon_api/views/list_view_test.exs index fb00310b9..59e896a7c 100644 --- a/test/web/mastodon_api/views/list_view_test.exs +++ b/test/web/mastodon_api/views/list_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ListViewTest do diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs index 977ea1e87..9231aaec8 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do diff --git a/test/web/mastodon_api/views/push_subscription_view_test.exs b/test/web/mastodon_api/views/push_subscription_view_test.exs index dc935fc82..4e4f5b7e6 100644 --- a/test/web/mastodon_api/views/push_subscription_view_test.exs +++ b/test/web/mastodon_api/views/push_subscription_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.PushSubscriptionViewTest do diff --git a/test/web/mastodon_api/views/scheduled_activity_view_test.exs b/test/web/mastodon_api/views/scheduled_activity_view_test.exs index ecbb855d4..6387e4555 100644 --- a/test/web/mastodon_api/views/scheduled_activity_view_test.exs +++ b/test/web/mastodon_api/views/scheduled_activity_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index fcdd7fbcb..51f8434fa 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.StatusViewTest do diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs index 53b8f556b..fdfdb5ec6 100644 --- a/test/web/media_proxy/media_proxy_controller_test.exs +++ b/test/web/media_proxy/media_proxy_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/web/media_proxy/media_proxy_test.exs index 79699cac5..96bdde219 100644 --- a/test/web/media_proxy/media_proxy_test.exs +++ b/test/web/media_proxy/media_proxy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MediaProxyTest do diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index f6147c286..e15a0bfff 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.NodeInfoTest do diff --git a/test/web/oauth/authorization_test.exs b/test/web/oauth/authorization_test.exs index d8b008437..2e82a7b79 100644 --- a/test/web/oauth/authorization_test.exs +++ b/test/web/oauth/authorization_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.AuthorizationTest do diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index b492c7794..2780e1746 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.OAuthControllerTest do diff --git a/test/web/oauth/token/utils_test.exs b/test/web/oauth/token/utils_test.exs index 20e338cab..dc1f9a986 100644 --- a/test/web/oauth/token/utils_test.exs +++ b/test/web/oauth/token/utils_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.Token.UtilsTest do diff --git a/test/web/oauth/token_test.exs b/test/web/oauth/token_test.exs index 3c07309b7..5359940f8 100644 --- a/test/web/oauth/token_test.exs +++ b/test/web/oauth/token_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.TokenTest do diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs index a3a92ce5b..a8d500890 100644 --- a/test/web/ostatus/activity_representer_test.exs +++ b/test/web/ostatus/activity_representer_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do diff --git a/test/web/ostatus/feed_representer_test.exs b/test/web/ostatus/feed_representer_test.exs index 3c7b126e7..d1cadf1e4 100644 --- a/test/web/ostatus/feed_representer_test.exs +++ b/test/web/ostatus/feed_representer_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus.FeedRepresenterTest do diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index 095ae7041..ec96f0012 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus.OStatusControllerTest do diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index 803a97695..f04a5cfc5 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatusTest do diff --git a/test/web/plugs/federating_plug_test.exs b/test/web/plugs/federating_plug_test.exs index bb2e1687a..9dcab93da 100644 --- a/test/web/plugs/federating_plug_test.exs +++ b/test/web/plugs/federating_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.FederatingPlugTest do diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index e2f89f40a..2f6ce4bd2 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Push.ImplTest do diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs index 0186f3fef..153ec41ac 100644 --- a/test/web/salmon/salmon_test.exs +++ b/test/web/salmon/salmon_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Salmon.SalmonTest do diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index 88847e20f..b8fcd41fa 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.StreamerTest do diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index 3c0528776..08f264431 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do diff --git a/test/web/uploader_controller_test.exs b/test/web/uploader_controller_test.exs index 70028df1c..7c7f9a6ea 100644 --- a/test/web/uploader_controller_test.exs +++ b/test/web/uploader_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.UploaderControllerTest do diff --git a/test/web/views/error_view_test.exs b/test/web/views/error_view_test.exs index 3857d585f..4e5398c83 100644 --- a/test/web/views/error_view_test.exs +++ b/test/web/views/error_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ErrorViewTest do diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/web/web_finger/web_finger_controller_test.exs index bd3ccaaf7..49cd1460b 100644 --- a/test/web/web_finger/web_finger_controller_test.exs +++ b/test/web/web_finger/web_finger_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs index 8fdb9adea..696c1bd70 100644 --- a/test/web/web_finger/web_finger_test.exs +++ b/test/web/web_finger/web_finger_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebFingerTest do diff --git a/test/web/websub/websub_controller_test.exs b/test/web/websub/websub_controller_test.exs index 59cacbe68..f6d002b3b 100644 --- a/test/web/websub/websub_controller_test.exs +++ b/test/web/websub/websub_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Websub.WebsubControllerTest do diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs index 929acf5a2..46ca545de 100644 --- a/test/web/websub/websub_test.exs +++ b/test/web/websub/websub_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebsubTest do From 3e972c0456a6f556bd1ee9118116f347d774df61 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 19 Sep 2019 00:21:16 +0300 Subject: [PATCH 180/272] Add :shared_pack_cache_seconds_per_file to description.exs --- config/description.exs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config/description.exs b/config/description.exs index 65ea6bf01..5dc8dc364 100644 --- a/config/description.exs +++ b/config/description.exs @@ -2256,6 +2256,14 @@ "Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download." <> " Currently only one manifest can be added (no arrays)", suggestions: ["https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"] + }, + %{ + key: :shared_pack_cache_seconds_per_file, + type: :integer, + descpiption: + "When an emoji pack is shared, the archive is created and cached in memory" <> + " for this amount of seconds multiplied by the number of files.", + suggestions: [60] } ] }, From fe5e0b784604b1352e98e7915c3c67d59ac4f709 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Thu, 19 Sep 2019 08:27:55 +0300 Subject: [PATCH 181/272] Mastodon API: Return `pleroma.direct_conversation_id` when creating direct messages (`POST /api/v1/statuses`) --- CHANGELOG.md | 1 + .../mastodon_api/controllers/mastodon_api_controller.ex | 7 ++++++- test/web/mastodon_api/mastodon_api_controller_test.exs | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 906aa985e..84b64e2b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Admin API: Return `total` when querying for reports +- Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) ## [1.1.0] - 2019-??-?? ### Security diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 37eeb2ac3..6704ee7e8 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -611,7 +611,12 @@ def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do {:ok, activity} -> conn |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + |> try_render("status.json", %{ + activity: activity, + for: user, + as: :activity, + with_direct_conversation_id: true + }) end end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index fb04748bb..35a0d3fe1 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -296,7 +296,9 @@ test "posting a direct status", %{conn: conn} do conn |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"}) - assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200) + assert %{"id" => id} = response = json_response(conn, 200) + assert response["visibility"] == "direct" + assert response["pleroma"]["direct_conversation_id"] assert activity = Activity.get_by_id(id) assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id] assert activity.data["to"] == [user2.ap_id] From cf3041220a7a14dc3fac24177fac1f4aecc77f5f Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 17 Sep 2019 15:22:46 +0700 Subject: [PATCH 182/272] Add support for `rel="ugc"` --- config/config.exs | 2 +- config/description.exs | 2 +- docs/config.md | 2 +- lib/pleroma/html.ex | 6 +++-- test/formatter_test.exs | 24 ++++++++++--------- test/web/common_api/common_api_utils_test.exs | 6 ++--- .../update_credentials_test.exs | 2 +- 7 files changed, 24 insertions(+), 20 deletions(-) diff --git a/config/config.exs b/config/config.exs index c7e0cf09f..26dc4d16d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -507,7 +507,7 @@ class: false, strip_prefix: false, new_window: false, - rel: false + rel: "ugc" ] config :pleroma, :ldap, diff --git a/config/description.exs b/config/description.exs index 65ea6bf01..abfb6370f 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1900,7 +1900,7 @@ key: :rel, type: [:string, false], description: "override the rel attribute. false to clear", - suggestions: ["noopener noreferrer", false] + suggestions: ["ugc", false] }, %{ key: :new_window, diff --git a/docs/config.md b/docs/config.md index 3f37fa561..def462900 100644 --- a/docs/config.md +++ b/docs/config.md @@ -521,7 +521,7 @@ config :auto_linker, class: false, strip_prefix: false, new_window: false, - rel: false + rel: "ugc" ] ``` diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 3951f0f51..937bafed5 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -184,7 +184,8 @@ defmodule Pleroma.HTML.Scrubber.Default do "tag", "nofollow", "noopener", - "noreferrer" + "noreferrer", + "ugc" ]) Meta.allow_tag_with_these_attributes("a", ["name", "title"]) @@ -304,7 +305,8 @@ defmodule Pleroma.HTML.Scrubber.LinksOnly do "nofollow", "noopener", "noreferrer", - "me" + "me", + "ugc" ]) Meta.allow_tag_with_these_attributes("a", ["name", "title"]) diff --git a/test/formatter_test.exs b/test/formatter_test.exs index c443dfe7c..3674577d6 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -39,21 +39,21 @@ test "turning urls into links" do text = "Hey, check out https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla ." expected = - "Hey, check out https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla ." + ~S(Hey, check out https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla .) assert {^expected, [], []} = Formatter.linkify(text) text = "https://mastodon.social/@lambadalambda" expected = - "https://mastodon.social/@lambadalambda" + ~S(https://mastodon.social/@lambadalambda) assert {^expected, [], []} = Formatter.linkify(text) text = "https://mastodon.social:4000/@lambadalambda" expected = - "https://mastodon.social:4000/@lambadalambda" + ~S(https://mastodon.social:4000/@lambadalambda) assert {^expected, [], []} = Formatter.linkify(text) @@ -63,55 +63,57 @@ test "turning urls into links" do assert {^expected, [], []} = Formatter.linkify(text) text = "http://www.cs.vu.nl/~ast/intel/" - expected = "http://www.cs.vu.nl/~ast/intel/" + + expected = + ~S(http://www.cs.vu.nl/~ast/intel/) assert {^expected, [], []} = Formatter.linkify(text) text = "https://forum.zdoom.org/viewtopic.php?f=44&t=57087" expected = - "https://forum.zdoom.org/viewtopic.php?f=44&t=57087" + "https://forum.zdoom.org/viewtopic.php?f=44&t=57087" assert {^expected, [], []} = Formatter.linkify(text) text = "https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul" expected = - "https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul" + "https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul" assert {^expected, [], []} = Formatter.linkify(text) text = "https://www.google.co.jp/search?q=Nasim+Aghdam" expected = - "https://www.google.co.jp/search?q=Nasim+Aghdam" + "https://www.google.co.jp/search?q=Nasim+Aghdam" assert {^expected, [], []} = Formatter.linkify(text) text = "https://en.wikipedia.org/wiki/Duff's_device" expected = - "https://en.wikipedia.org/wiki/Duff's_device" + "https://en.wikipedia.org/wiki/Duff's_device" assert {^expected, [], []} = Formatter.linkify(text) text = "https://pleroma.com https://pleroma.com/sucks" expected = - "https://pleroma.com https://pleroma.com/sucks" + "https://pleroma.com https://pleroma.com/sucks" assert {^expected, [], []} = Formatter.linkify(text) text = "xmpp:contact@hacktivis.me" - expected = "xmpp:contact@hacktivis.me" + expected = "xmpp:contact@hacktivis.me" assert {^expected, [], []} = Formatter.linkify(text) text = "magnet:?xt=urn:btih:7ec9d298e91d6e4394d1379caf073c77ff3e3136&tr=udp%3A%2F%2Fopentor.org%3A2710&tr=udp%3A%2F%2Ftracker.blackunicorn.xyz%3A6969&tr=udp%3A%2F%2Ftracker.ccc.de%3A80&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com" - expected = "#{text}" + expected = "#{text}" assert {^expected, [], []} = Formatter.linkify(text) end diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index 230146451..78cfe3c5f 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -157,11 +157,11 @@ test "works for text/markdown with mentions" do text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*" expected = - "

hello world

\n

another hello world

\n

another @user__test and @user__test and @user__test google.com paragraph

\n" + }" class="u-url mention" href="http://foo.com/user__test">@user__test google.com paragraph

\n) {output, _, _} = Utils.format_input(text, "text/markdown") diff --git a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs index 89d4ca37e..1e8d0d03b 100644 --- a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs @@ -334,7 +334,7 @@ test "update fields", %{conn: conn} do assert account["fields"] == [ %{"name" => "foo", "value" => "bar"}, - %{"name" => "link", "value" => "cofe.io"} + %{"name" => "link", "value" => ~S(cofe.io)} ] assert account["source"]["fields"] == [ From d639cdcecb1b9cd2326b98c926dff8b0f4c27e3c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 19 Sep 2019 14:04:13 +0700 Subject: [PATCH 183/272] Update "config/description.exs" --- config/description.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/description.exs b/config/description.exs index abfb6370f..510e285df 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1900,7 +1900,7 @@ key: :rel, type: [:string, false], description: "override the rel attribute. false to clear", - suggestions: ["ugc", false] + suggestions: ["ugc", "noopener noreferrer", false] }, %{ key: :new_window, From 95c948110ca130559fd6a5302011aa58900274ac Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 19 Sep 2019 14:39:52 +0700 Subject: [PATCH 184/272] Add `rel="ugc"` to hashtags and mentions --- lib/pleroma/formatter.ex | 6 ++-- test/formatter_test.exs | 30 +++++++++++-------- test/user_test.exs | 4 +-- test/web/common_api/common_api_utils_test.exs | 4 +-- .../update_credentials_test.exs | 7 ++--- .../mastodon_api_controller_test.exs | 8 ++--- test/web/twitter_api/twitter_api_test.exs | 4 ++- 7 files changed, 35 insertions(+), 28 deletions(-) diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 607843a5b..23a5ac8fe 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -36,9 +36,9 @@ def mention_handler("@" <> nickname, buffer, opts, acc) do nickname_text = get_nickname_text(nickname, opts) link = - "@#{ + ~s(@#{ nickname_text - }" + }) {link, %{acc | mentions: MapSet.put(acc.mentions, {"@" <> nickname, user})}} @@ -50,7 +50,7 @@ def mention_handler("@" <> nickname, buffer, opts, acc) do def hashtag_handler("#" <> tag = tag_text, _buffer, _opts, acc) do tag = String.downcase(tag) url = "#{Pleroma.Web.base_url()}/tag/#{tag}" - link = "" + link = ~s(#{tag_text}) {link, %{acc | tags: MapSet.put(acc.tags, {tag_text, tag})}} end diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 3674577d6..2e4280fc2 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -19,7 +19,7 @@ test "turns hashtags into links" do text = "I love #cofe and #2hu" expected_text = - "I love and " + ~s(I love #cofe and #2hu) assert {^expected_text, [], _tags} = Formatter.linkify(text) end @@ -28,7 +28,7 @@ test "does not turn html characters to tags" do text = "#fact_3: pleroma does what mastodon't" expected_text = - ": pleroma does what mastodon't" + ~s(#fact_3: pleroma does what mastodon't) assert {^expected_text, [], _tags} = Formatter.linkify(text) end @@ -137,13 +137,13 @@ test "gives a replacement for user links, using local nicknames in user links te assert length(mentions) == 3 expected_text = - "@gsimg According to @archa_eme_, that is @daggsy. Also hello @archaeme" + }" class="u-url mention" href="#{archaeme_remote.ap_id}" rel="ugc">@archaeme) assert expected_text == text end @@ -158,7 +158,9 @@ test "gives a replacement for user links when the user is using Osada" do assert length(mentions) == 1 expected_text = - "@mike test" + ~s(@mike test) assert expected_text == text end @@ -172,7 +174,7 @@ test "gives a replacement for single-character local nicknames" do assert length(mentions) == 1 expected_text = - "@o hi" + ~s(@o hi) assert expected_text == text end @@ -194,13 +196,17 @@ test "given the 'safe_mention' option, it will only mention people in the beginn assert mentions == [{"@#{user.nickname}", user}, {"@#{other_user.nickname}", other_user}] assert expected_text == - "@#{user.nickname} @#{other_user.nickname} hey dudes i hate @#{third_user.nickname}" + }" class="u-url mention" href="#{third_user.ap_id}" rel="ugc">@#{ + third_user.nickname + }) end test "given the 'safe_mention' option, it will still work without any mention" do diff --git a/test/user_test.exs b/test/user_test.exs index 39ba69668..6852fcd40 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1294,9 +1294,9 @@ test "preserves hosts in user links text" do bio = "A.k.a. @nick@domain.com" expected_text = - "A.k.a. @nick@domain.com" + }" rel="ugc">@nick@domain.com) assert expected_text == User.parse_bio(bio, user) end diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index 78cfe3c5f..2588898d0 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -159,9 +159,9 @@ test "works for text/markdown with mentions" do expected = ~s(

hello world

\n

another @user__test and @user__test and @user__test google.com paragraph

\n) + }" class="u-url mention" href="http://foo.com/user__test" rel="ugc">@user__test google.com paragraph

\n) {output, _, _} = Utils.format_input(text, "text/markdown") diff --git a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs index 1e8d0d03b..560f55137 100644 --- a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs @@ -86,10 +86,9 @@ test "updates the user's bio", %{conn: conn} do assert user = json_response(conn, 200) assert user["note"] == - ~s(I drink with @) <> user2.nickname <> ~s() + ~s(I drink #cofe with @#{user2.nickname}) end test "updates the user's locking status", %{conn: conn} do diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index fb04748bb..b85f3e758 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -996,9 +996,9 @@ test "list of notifications", %{conn: conn} do |> get("/api/v1/notifications") expected_response = - "hi @#{user.nickname}" + }" rel="ugc">@#{user.nickname}) assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) assert response == expected_response @@ -1018,9 +1018,9 @@ test "getting a single notification", %{conn: conn} do |> get("/api/v1/notifications/#{notification.id}") expected_response = - "hi @#{user.nickname}" + }" rel="ugc">@#{user.nickname}) assert %{"status" => %{"content" => response}} = json_response(conn, 200) assert response == expected_response diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index 08f264431..bf1e233f5 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -109,7 +109,9 @@ test "it registers a new user and parses mentions in the bio" do {:ok, user2} = TwitterAPI.register_user(data2) expected_text = - "@john test" + ~s(@john test) assert user2.bio == expected_text end From ae1d371428e16b738b8ec638e411e5e8c1ac4937 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 19 Sep 2019 14:53:34 +0700 Subject: [PATCH 185/272] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 906aa985e..f84b0ac68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) - Improve digest email template – Pagination: (optional) return `total` alongside with `items` when paginating +- Add `rel="ugc"` to all links in statuses, to prevent SEO spam ### Fixed - Following from Osada From 0e6085da106cb966c340fac2d307d9e8e26e91ed Mon Sep 17 00:00:00 2001 From: D Anzorge Date: Thu, 19 Sep 2019 16:09:07 +0200 Subject: [PATCH 186/272] Fix pagination in AP outbox.json --- lib/pleroma/web/activity_pub/views/user_view.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 164b973d0..a2f73e140 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -227,11 +227,12 @@ def render("outbox.json", %{user: user, max_id: max_qid}) do activities = ActivityPub.fetch_user_activities(user, nil, params) + # this is sorted chronologically, so first activity is the newest (max) {max_id, min_id, collection} = if length(activities) > 0 do { - Enum.at(Enum.reverse(activities), 0).id, Enum.at(activities, 0).id, + Enum.at(Enum.reverse(activities), 0).id, Enum.map(activities, fn act -> {:ok, data} = Transmogrifier.prepare_outgoing(act.data) data From 9aca2cc95d0d8886d35be17e5cdd683004b425d9 Mon Sep 17 00:00:00 2001 From: D Anzorge Date: Thu, 19 Sep 2019 16:09:24 +0200 Subject: [PATCH 187/272] Add test for correct AP outbox pagination --- .../web/activity_pub/views/user_view_test.exs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 2b4a04afd..eda95e3ea 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -142,4 +142,27 @@ test "sets correct totalItems when follows are hidden but the follow counter is assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) end end + + test "outbox paginates correctly" do + user = insert(:user) + + posts = + for i <- 0..25 do + {:ok, activity} = CommonAPI.post(user, %{"status" => "post #{i}"}) + activity + end + + # outbox sorts chronologically, newest first, with ten per page + posts = Enum.reverse(posts) + + %{"first" => %{"next" => next_url}} = + UserView.render("outbox.json", %{user: user, max_id: nil}) + + next_id = Enum.at(posts, 9).id + assert next_url =~ next_id + + %{"next" => next_url} = UserView.render("outbox.json", %{user: user, max_id: next_id}) + next_id = Enum.at(posts, 19).id + assert next_url =~ next_id + end end From fe4db3b94e71bafb913044de543472764671cd1a Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 19 Sep 2019 21:01:05 +0200 Subject: [PATCH 188/272] API Docs: Document conversation ids. --- docs/api/differences_in_mastoapi_responses.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 3c7f5dad7..d007a69c3 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -21,7 +21,8 @@ Adding the parameter `with_muted=true` to the timeline queries will also return Has these additional fields under the `pleroma` object: - `local`: true if the post was made on the local instance -- `conversation_id`: the ID of the conversation the status is associated with (if any) +- `conversation_id`: the ID of the AP context the status is associated with (if any) +- `direct_conversation_id`: the ID of the Mastodon direct message conversation the status is associated with (if any) - `in_reply_to_account_acct`: the `acct` property of User entity for replied user (if any) - `content`: a map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain` - `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain` From df3feb9412f1a6b9962aa5ad4a45e73aabc486d7 Mon Sep 17 00:00:00 2001 From: feld Date: Fri, 20 Sep 2019 13:21:07 +0000 Subject: [PATCH 189/272] Make it obvious how to support dual stack for MongooseIM --- installation/pleroma-mongooseim.cfg | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/installation/pleroma-mongooseim.cfg b/installation/pleroma-mongooseim.cfg index d7567321f..576f83541 100755 --- a/installation/pleroma-mongooseim.cfg +++ b/installation/pleroma-mongooseim.cfg @@ -215,7 +215,9 @@ ]} ]}, - { 5222, ejabberd_c2s, [ + %% If you want dual stack, you have to clone this entire config stanza + %% and change the bind to "::" + { {5222, "0.0.0.0"}, ejabberd_c2s, [ %% %% If TLS is compiled in and you installed a SSL @@ -246,7 +248,9 @@ %% {max_stanza_size, 65536} %% ]}, - { 5269, ejabberd_s2s_in, [ + %% If you want dual stack, you have to clone this entire config stanza + %% and change the bind to "::" + { {5269, "0.0.0.0"}, ejabberd_s2s_in, [ {shaper, s2s_shaper}, {max_stanza_size, 131072}, {protocol_options, ["no_sslv3"]} From 7cf125245512eb49a118535eda52ddbdd0c4c6bf Mon Sep 17 00:00:00 2001 From: eugenijm Date: Fri, 20 Sep 2019 17:54:38 +0300 Subject: [PATCH 190/272] Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) --- CHANGELOG.md | 2 ++ lib/pleroma/web/activity_pub/activity_pub.ex | 5 +++-- .../controllers/mastodon_api_controller.ex | 1 - .../mastodon_api_controller_test.exs | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84b64e2b9..93b7e2a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Admin API: Return `total` when querying for reports - Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) +### Fixed +- Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) ## [1.1.0] - 2019-??-?? ### Security diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e1e90d667..1cf8b6151 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -520,9 +520,10 @@ def fetch_latest_activity_id_for_context(context, opts \\ %{}) do end def fetch_public_activities(opts \\ %{}) do - q = fetch_activities_query([Pleroma.Constants.as_public()], opts) + opts = Map.drop(opts, ["user"]) - q + [Pleroma.Constants.as_public()] + |> fetch_activities_query(opts) |> restrict_unlisted() |> Pagination.fetch_paginated(opts) |> Enum.reverse() diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 6704ee7e8..6421c2c53 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -381,7 +381,6 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do |> Map.put("local_only", local_only) |> Map.put("blocking_user", user) |> Map.put("muting_user", user) - |> Map.put("user", user) |> ActivityPub.fetch_public_activities() |> Enum.reverse() diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 35a0d3fe1..51f5215c2 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -97,6 +97,22 @@ test "the public timeline when public is set to false", %{conn: conn} do |> json_response(403) == %{"error" => "This resource requires authentication."} end + test "the public timeline includes only public statuses for an authenticated user" do + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"}) + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"}) + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"}) + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) + + res_conn = get(conn, "/api/v1/timelines/public") + assert length(json_response(res_conn, 200)) == 1 + end + describe "posting statuses" do setup do user = insert(:user) From 6f25668215f7f9fe20bfaf3dd72e2262a6d8915e Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 22 Sep 2019 16:08:07 +0300 Subject: [PATCH 191/272] Admin API: Add ability to force user's password reset --- CHANGELOG.md | 2 ++ docs/api/admin_api.md | 8 ++++++ lib/pleroma/user.ex | 17 ++++++++++++ lib/pleroma/user/info.ex | 13 ++++++--- .../web/admin_api/admin_api_controller.ex | 9 +++++++ lib/pleroma/web/oauth/oauth_controller.ex | 5 ++++ lib/pleroma/web/router.ex | 1 + lib/pleroma/workers/background_worker.ex | 5 ++++ test/user_test.exs | 17 ++++++++++++ .../admin_api/admin_api_controller_test.exs | 26 ++++++++++++++++++ test/web/oauth/oauth_controller_test.exs | 27 +++++++++++++++++++ .../twitter_api/password_controller_test.exs | 21 +++++++++++++++ 12 files changed, 148 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84b64e2b9..e5a84f5ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Added - Refreshing poll results for remote polls +- Admin API: Add ability to force user's password reset + ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) - Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 7637fa0d4..c6b9dd2b6 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -310,6 +310,14 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Params: none - Response: password reset token (base64 string) +## `/api/pleroma/admin/users/:nickname/force_password_reset` + +### Force passord reset for a user with a given nickname + +- Methods: `PATCH` +- Params: none +- Response: none (code `204`) + ## `/api/pleroma/admin/reports` ### Get a list of reports - Method `GET` diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fb1f24254..ab253a274 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -269,6 +269,7 @@ def password_update_changeset(struct, params) do |> validate_required([:password, :password_confirmation]) |> validate_confirmation(:password) |> put_password_hash + |> put_embed(:info, User.Info.set_password_reset_pending(struct.info, false)) end @spec reset_password(User.t(), map) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()} @@ -285,6 +286,20 @@ def reset_password(%User{id: user_id} = user, data) do end end + def force_password_reset_async(user) do + BackgroundWorker.enqueue("force_password_reset", %{"user_id" => user.id}) + end + + @spec force_password_reset(User.t()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()} + def force_password_reset(user) do + info_cng = User.Info.set_password_reset_pending(user.info, true) + + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end + def register_changeset(struct, params \\ %{}, opts \\ []) do bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) @@ -1115,6 +1130,8 @@ def delete(%User{} = user) do BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id}) end + def perform(:force_password_reset, user), do: force_password_reset(user) + @spec perform(atom(), User.t()) :: {:ok, User.t()} def perform(:delete, %User{} = user) do {:ok, _user} = ActivityPub.delete(user) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index b150a57cd..67abc3ecd 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -20,6 +20,7 @@ defmodule Pleroma.User.Info do field(:following_count, :integer, default: nil) field(:locked, :boolean, default: false) field(:confirmation_pending, :boolean, default: false) + field(:password_reset_pending, :boolean, default: false) field(:confirmation_token, :string, default: nil) field(:default_scope, :string, default: "public") field(:blocks, {:array, :string}, default: []) @@ -82,6 +83,14 @@ def set_activation_status(info, deactivated) do |> validate_required([:deactivated]) end + def set_password_reset_pending(info, pending) do + params = %{password_reset_pending: pending} + + info + |> cast(params, [:password_reset_pending]) + |> validate_required([:password_reset_pending]) + end + def update_notification_settings(info, settings) do settings = settings @@ -333,9 +342,7 @@ defp valid_field?(%{"name" => name, "value" => value}) do name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255) value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) - is_binary(name) && - is_binary(value) && - String.length(name) <= name_limit && + is_binary(name) && is_binary(value) && String.length(name) <= name_limit && String.length(value) <= value_limit end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 8a8091daa..711e4dfc2 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -447,6 +447,15 @@ def get_password_reset(conn, %{"nickname" => nickname}) do |> json(token.token) end + @doc "Force password reset for a given user" + def force_password_reset(conn, %{"nickname" => nickname}) do + (%User{local: true} = user) = User.get_cached_by_nickname(nickname) + + User.force_password_reset_async(user) + + json_response(conn, :no_content, "") + end + def list_reports(conn, params) do params = params diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 81eae2c8b..a57670e02 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -202,6 +202,8 @@ def token_exchange( {:ok, app} <- Token.Utils.fetch_app(conn), {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, {:user_active, true} <- {:user_active, !user.info.deactivated}, + {:password_reset_pending, false} <- + {:password_reset_pending, user.info.password_reset_pending}, {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do @@ -215,6 +217,9 @@ def token_exchange( {:user_active, false} -> render_error(conn, :forbidden, "Your account is currently disabled") + {:password_reset_pending, true} -> + render_error(conn, :forbidden, "Password reset is required") + _error -> render_invalid_credentials_error(conn) end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b9b85fd67..a306c1b80 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -186,6 +186,7 @@ defmodule Pleroma.Web.Router do post("/users/email_invite", AdminAPIController, :email_invite) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) + patch("/users/:nickname/force_password_reset", AdminAPIController, :force_password_reset) get("/users", AdminAPIController, :list_users) get("/users/:nickname", AdminAPIController, :user_show) diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 082f20ab7..7ffc8eabe 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -26,6 +26,11 @@ def perform(%{"op" => "delete_user", "user_id" => user_id}, _job) do User.perform(:delete, user) end + def perform(%{"op" => "force_password_reset", "user_id" => user_id}, _job) do + user = User.get_cached_by_id(user_id) + User.perform(:force_password_reset, user) + end + def perform( %{ "op" => "blocks_import", diff --git a/test/user_test.exs b/test/user_test.exs index 39ba69668..164172405 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1690,4 +1690,21 @@ test "changes email", %{user: user} do assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party") end end + + describe "set_password_reset_pending/2" do + setup do + [user: insert(:user)] + end + + test "sets password_reset_pending to true", %{user: user} do + %{password_reset_pending: password_reset_pending} = user.info + + refute password_reset_pending + + {:ok, %{info: %{password_reset_pending: password_reset_pending}}} = + User.force_password_reset(user) + + assert password_reset_pending + end + end end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 108143f6a..f00e02a7a 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -4,11 +4,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Activity alias Pleroma.HTML alias Pleroma.ModerationLog alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.UserInviteToken alias Pleroma.Web.CommonAPI @@ -2351,6 +2353,30 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do "@#{admin.nickname} followed relay: https://example.org/relay" end end + + describe "PATCH /users/:nickname/force_password_reset" do + setup %{conn: conn} do + admin = insert(:user, info: %{is_admin: true}) + user = insert(:user) + + %{conn: assign(conn, :user, admin), admin: admin, user: user} + end + + test "sets password_reset_pending to true", %{admin: admin, user: user} do + assert user.info.password_reset_pending == false + + conn = + build_conn() + |> assign(:user, admin) + |> patch("/api/pleroma/admin/users/#{user.nickname}/force_password_reset") + + assert json_response(conn, 204) == "" + + ObanHelpers.perform_all() + + assert User.get_by_id(user.id).info.password_reset_pending == true + end + end end # Needed for testing diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index 2780e1746..8b88fd784 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -831,6 +831,33 @@ test "rejects token exchange for valid credentials belonging to deactivated user refute Map.has_key?(resp, "access_token") end + test "rejects token exchange for user with password_reset_pending set to true" do + password = "testpassword" + + user = + insert(:user, + password_hash: Comeonin.Pbkdf2.hashpwsalt(password), + info: %{password_reset_pending: true} + ) + + app = insert(:oauth_app, scopes: ["read", "write"]) + + conn = + build_conn() + |> post("/oauth/token", %{ + "grant_type" => "password", + "username" => user.nickname, + "password" => password, + "client_id" => app.client_id, + "client_secret" => app.client_secret + }) + + assert resp = json_response(conn, 403) + + assert resp["error"] == "Password reset is required" + refute Map.has_key?(resp, "access_token") + end + test "rejects an invalid authorization code" do app = insert(:oauth_app) diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs index 3a7246ea8..dc6d4e3e3 100644 --- a/test/web/twitter_api/password_controller_test.exs +++ b/test/web/twitter_api/password_controller_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do use Pleroma.Web.ConnCase alias Pleroma.PasswordResetToken + alias Pleroma.User alias Pleroma.Web.OAuth.Token import Pleroma.Factory @@ -56,5 +57,25 @@ test "it returns HTTP 200", %{conn: conn} do assert Comeonin.Pbkdf2.checkpw("test", user.password_hash) assert length(Token.get_user_tokens(user)) == 0 end + + test "it sets password_reset_pending to false", %{conn: conn} do + user = insert(:user, info: %{password_reset_pending: true}) + + {:ok, token} = PasswordResetToken.create_token(user) + {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{}) + + params = %{ + "password" => "test", + password_confirmation: "test", + token: token.token + } + + conn + |> assign(:user, user) + |> post("/api/pleroma/password_reset", %{data: params}) + |> html_response(:ok) + + assert User.get_by_id(user.id).info.password_reset_pending == false + end end end From 72a01f1350239d286978007883a087f8f3985d1b Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 22 Sep 2019 16:36:59 +0300 Subject: [PATCH 192/272] Use router helper to generate reset password link --- lib/pleroma/web/admin_api/admin_api_controller.ex | 6 +++--- test/web/admin_api/admin_api_controller_test.exs | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 54ab6e032..b2df1e5b8 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -17,7 +17,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.AdminAPI.ReportView alias Pleroma.Web.AdminAPI.Search alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Endpoint alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.Router import Pleroma.Web.ControllerHelper, only: [json_response: 3] @@ -432,13 +434,11 @@ def revoke_invite(conn, %{"token" => token}) do def get_password_reset(conn, %{"nickname" => nickname}) do (%User{local: true} = user) = User.get_cached_by_nickname(nickname) {:ok, token} = Pleroma.PasswordResetToken.create_token(user) - host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host]) - protocol = Pleroma.Config.get([Pleroma.Web.Endpoint, :protocol]) conn |> json(%{ token: token.token, - link: "#{protocol}://#{host}/api/pleroma/password_reset/#{token.token}" + link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token) }) end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index c497ea098..77c67011d 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -596,7 +596,9 @@ test "/api/pleroma/admin/users/:nickname/password_reset" do |> put_req_header("accept", "application/json") |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") - assert conn.status == 200 + resp = json_response(conn, 200) + + assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) end describe "GET /api/pleroma/admin/users" do From f89fe3ac06505cc07372fcdefdc3fde72d1f04a0 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 22 Sep 2019 16:45:38 +0300 Subject: [PATCH 193/272] Update docs --- docs/api/admin_api.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 9362e3d78..8bc6379aa 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -298,7 +298,15 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Methods: `GET` - Params: none -- Response: password reset token (base64 string) +- Response: + +```json +{ + "token": "U13DX6muOvpRsj35_ij9wLxUbkU-eFvfKttxs6gIajo=", // password reset token (base64 string) + "link": "https://pleroma.social/api/pleroma/password_reset/U13DX6muOvpRsj35_ij9wLxUbkU-eFvfKttxs6gIajo%3D" +} +``` + ## `/api/pleroma/admin/reports` ### Get a list of reports From c8fdf757c124ac053307b0b4e02a38fc40e2dc58 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 22 Sep 2019 16:59:37 +0300 Subject: [PATCH 194/272] I did not put these lines in CHANGELOG --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a05dadb..6c31c0075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Refreshing poll results for remote polls ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) -- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) -- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Admin API: Return `total` when querying for reports - Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) From 79c3443b609663ab23a4353ebdb7e5e2f0e6a150 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 22 Sep 2019 17:00:49 +0300 Subject: [PATCH 195/272] Update CHANGELOG --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c31c0075..e816e1394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Refreshing poll results for remote polls ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) +- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) +- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Admin API: Return `total` when querying for reports - Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) +- Admin API: Return link alongside with token on password reset ## [1.1.0] - 2019-??-?? ### Security @@ -37,9 +40,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) - Improve digest email template – Pagination: (optional) return `total` alongside with `items` when paginating -- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) -- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler -- Admin API: Return link alongside with token on password reset ### Fixed - Following from Osada From d72d4757a8e66c29d58e0a3b7fb36356ae419a54 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 22 Sep 2019 23:13:48 +0300 Subject: [PATCH 196/272] Format --- lib/pleroma/user/info.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 67abc3ecd..99745f496 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -342,7 +342,9 @@ defp valid_field?(%{"name" => name, "value" => value}) do name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255) value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) - is_binary(name) && is_binary(value) && String.length(name) <= name_limit && + is_binary(name) && + is_binary(value) && + String.length(name) <= name_limit && String.length(value) <= value_limit end From cf1960d5961a3a01a6d92c44ab4a6d0ce9570a09 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 22 Sep 2019 23:14:18 +0300 Subject: [PATCH 197/272] Better changelog wording --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5a84f5ae..f28299666 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Added - Refreshing poll results for remote polls -- Admin API: Add ability to force user's password reset +- Admin API: Add ability to require password reset ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) From 6b3d5ed6db6a3c73eb1f8373ebd670427aa8849d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 23 Sep 2019 21:14:51 +0300 Subject: [PATCH 198/272] Emoji API Controller: Follow phoenix directory structure --- .../web/pleroma_api/{ => controllers}/emoji_api_controller.ex | 0 .../web/pleroma_api/{ => controllers}/pleroma_api_controller.ex | 0 test/web/{ => pleroma_api}/emoji_api_controller_test.exs | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename lib/pleroma/web/pleroma_api/{ => controllers}/emoji_api_controller.ex (100%) rename lib/pleroma/web/pleroma_api/{ => controllers}/pleroma_api_controller.ex (100%) rename test/web/{ => pleroma_api}/emoji_api_controller_test.exs (100%) diff --git a/lib/pleroma/web/pleroma_api/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex similarity index 100% rename from lib/pleroma/web/pleroma_api/emoji_api_controller.ex rename to lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex similarity index 100% rename from lib/pleroma/web/pleroma_api/pleroma_api_controller.ex rename to lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex diff --git a/test/web/emoji_api_controller_test.exs b/test/web/pleroma_api/emoji_api_controller_test.exs similarity index 100% rename from test/web/emoji_api_controller_test.exs rename to test/web/pleroma_api/emoji_api_controller_test.exs From 646bf0160893f01fe14d1d38f24420ac6c962804 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 23 Sep 2019 21:13:39 +0200 Subject: [PATCH 199/272] Update AdminFE bundle --- .../{app.34fc670f.css => app.40438ff5.css} | Bin 12809 -> 12809 bytes priv/static/adminfe/chunk-06db.75709645.css | Bin 0 -> 2044 bytes priv/static/adminfe/chunk-15fa.bcc01554.css | Bin 0 -> 4748 bytes priv/static/adminfe/chunk-1a7d.38eb00cf.css | Bin 0 -> 480 bytes ...1.6aaab273.css => chunk-1f27.c0efd1fc.css} | Bin priv/static/adminfe/chunk-2325.0d22684d.css | Bin 4748 -> 0 bytes ...8.e12401fb.css => chunk-3d1c.2880a519.css} | Bin priv/static/adminfe/chunk-5913.33f0e7ff.css | Bin 0 -> 3252 bytes ...f.d7a1893c.css => chunk-598f.dc5869e7.css} | Bin ...7.ac97b15a.css => chunk-6292.d1c82a11.css} | Bin priv/static/adminfe/chunk-7c6b.4a8663a9.css | Bin 0 -> 1737 bytes priv/static/adminfe/chunk-8b70.9ba0945c.css | Bin 1865 -> 0 bytes priv/static/adminfe/chunk-e547.e4b6230b.css | Bin 3304 -> 0 bytes ...d8da6.css => chunk-elementUI.f35d8ab1.css} | Bin ...s.4e8c4664.css => chunk-libs.00388c73.css} | Bin priv/static/adminfe/index.html | 2 +- .../static/adminfe/static/js/7zzA.e1ae1c94.js | Bin 374 -> 416 bytes .../adminfe/static/js/7zzA.e1ae1c94.js.map | Bin 0 -> 1913 bytes .../static/adminfe/static/js/JEtC.f9ba4594.js | Bin 388 -> 430 bytes .../adminfe/static/js/JEtC.f9ba4594.js.map | Bin 0 -> 1903 bytes priv/static/adminfe/static/js/app.8e186193.js | Bin 137815 -> 0 bytes priv/static/adminfe/static/js/app.90c455c5.js | Bin 0 -> 161629 bytes .../adminfe/static/js/app.90c455c5.js.map | Bin 0 -> 354948 bytes .../adminfe/static/js/chunk-02a0.db6ec114.js | Bin 266229 -> 0 bytes .../adminfe/static/js/chunk-0620.c765c190.js | Bin 12982 -> 13030 bytes .../static/js/chunk-0620.c765c190.js.map | Bin 0 -> 63567 bytes .../adminfe/static/js/chunk-06db.12facc20.js | Bin 0 -> 5112 bytes .../static/js/chunk-06db.12facc20.js.map | Bin 0 -> 19586 bytes .../adminfe/static/js/chunk-15fa.b0633695.js | Bin 0 -> 7919 bytes .../static/js/chunk-15fa.b0633695.js.map | Bin 0 -> 17438 bytes .../adminfe/static/js/chunk-16d0.6ce78978.js | Bin 0 -> 1576 bytes .../static/js/chunk-16d0.6ce78978.js.map | Bin 0 -> 4426 bytes .../adminfe/static/js/chunk-1a7d.8173d81f.js | Bin 0 -> 16157 bytes .../static/js/chunk-1a7d.8173d81f.js.map | Bin 0 -> 57112 bytes ...8e1.7f9c377c.js => chunk-1f27.d3c35fbc.js} | Bin 2032 -> 2080 bytes .../static/js/chunk-1f27.d3c35fbc.js.map | Bin 0 -> 9090 bytes .../adminfe/static/js/chunk-2325.154a537b.js | Bin 8220 -> 0 bytes ...e18.208cd826.js => chunk-3d1c.20303ef7.js} | Bin 4774 -> 4822 bytes .../static/js/chunk-3d1c.20303ef7.js.map | Bin 0 -> 18519 bytes .../adminfe/static/js/chunk-5913.1d21a547.js | Bin 0 -> 27091 bytes .../static/js/chunk-5913.1d21a547.js.map | Bin 0 -> 88770 bytes ...fbf.616fb309.js => chunk-598f.dd8089ce.js} | Bin 17717 -> 17765 bytes .../static/js/chunk-598f.dd8089ce.js.map | Bin 0 -> 66937 bytes .../adminfe/static/js/chunk-5e57.7313703a.js | Bin 217441 -> 0 bytes .../adminfe/static/js/chunk-6292.0e668979.js | Bin 0 -> 231394 bytes .../static/js/chunk-6292.0e668979.js.map | Bin 0 -> 689117 bytes .../adminfe/static/js/chunk-7c6b.c306c730.js | Bin 0 -> 7947 bytes .../static/js/chunk-7c6b.c306c730.js.map | Bin 0 -> 26432 bytes .../adminfe/static/js/chunk-7fe2.458f9da5.js | Bin 408401 -> 408449 bytes .../static/js/chunk-7fe2.458f9da5.js.map | Bin 0 -> 1242154 bytes .../adminfe/static/js/chunk-8b70.46525646.js | Bin 3190 -> 0 bytes .../adminfe/static/js/chunk-df62.6c5105a6.js | Bin 0 -> 265970 bytes .../static/js/chunk-df62.6c5105a6.js.map | Bin 0 -> 796489 bytes .../adminfe/static/js/chunk-e547.d57d1b91.js | Bin 23125 -> 0 bytes ...911151b.js => chunk-elementUI.708d6b68.js} | Bin 638883 -> 638936 bytes .../static/js/chunk-elementUI.708d6b68.js.map | Bin 0 -> 2312798 bytes .../adminfe/static/js/chunk-libs.14514767.js | Bin 0 -> 275816 bytes .../static/js/chunk-libs.14514767.js.map | Bin 0 -> 1641569 bytes .../adminfe/static/js/chunk-libs.fb0b7f4a.js | Bin 204635 -> 0 bytes .../static/adminfe/static/js/oAJy.840fb1c2.js | Bin 0 -> 28900 bytes .../adminfe/static/js/oAJy.840fb1c2.js.map | Bin 0 -> 135594 bytes .../adminfe/static/js/runtime.e85850af.js | Bin 0 -> 3859 bytes .../adminfe/static/js/runtime.e85850af.js.map | Bin 0 -> 16537 bytes .../adminfe/static/js/runtime.f40c8ec4.js | Bin 3608 -> 0 bytes 64 files changed, 1 insertion(+), 1 deletion(-) rename priv/static/adminfe/{app.34fc670f.css => app.40438ff5.css} (92%) create mode 100644 priv/static/adminfe/chunk-06db.75709645.css create mode 100644 priv/static/adminfe/chunk-15fa.bcc01554.css create mode 100644 priv/static/adminfe/chunk-1a7d.38eb00cf.css rename priv/static/adminfe/{chunk-18e1.6aaab273.css => chunk-1f27.c0efd1fc.css} (100%) delete mode 100644 priv/static/adminfe/chunk-2325.0d22684d.css rename priv/static/adminfe/{chunk-0e18.e12401fb.css => chunk-3d1c.2880a519.css} (100%) create mode 100644 priv/static/adminfe/chunk-5913.33f0e7ff.css rename priv/static/adminfe/{chunk-1fbf.d7a1893c.css => chunk-598f.dc5869e7.css} (100%) rename priv/static/adminfe/{chunk-5e57.ac97b15a.css => chunk-6292.d1c82a11.css} (100%) create mode 100644 priv/static/adminfe/chunk-7c6b.4a8663a9.css delete mode 100644 priv/static/adminfe/chunk-8b70.9ba0945c.css delete mode 100644 priv/static/adminfe/chunk-e547.e4b6230b.css rename priv/static/adminfe/{chunk-elementUI.e5cd8da6.css => chunk-elementUI.f35d8ab1.css} (100%) rename priv/static/adminfe/{chunk-libs.4e8c4664.css => chunk-libs.00388c73.css} (100%) create mode 100644 priv/static/adminfe/static/js/7zzA.e1ae1c94.js.map create mode 100644 priv/static/adminfe/static/js/JEtC.f9ba4594.js.map delete mode 100644 priv/static/adminfe/static/js/app.8e186193.js create mode 100644 priv/static/adminfe/static/js/app.90c455c5.js create mode 100644 priv/static/adminfe/static/js/app.90c455c5.js.map delete mode 100644 priv/static/adminfe/static/js/chunk-02a0.db6ec114.js create mode 100644 priv/static/adminfe/static/js/chunk-0620.c765c190.js.map create mode 100644 priv/static/adminfe/static/js/chunk-06db.12facc20.js create mode 100644 priv/static/adminfe/static/js/chunk-06db.12facc20.js.map create mode 100644 priv/static/adminfe/static/js/chunk-15fa.b0633695.js create mode 100644 priv/static/adminfe/static/js/chunk-15fa.b0633695.js.map create mode 100644 priv/static/adminfe/static/js/chunk-16d0.6ce78978.js create mode 100644 priv/static/adminfe/static/js/chunk-16d0.6ce78978.js.map create mode 100644 priv/static/adminfe/static/js/chunk-1a7d.8173d81f.js create mode 100644 priv/static/adminfe/static/js/chunk-1a7d.8173d81f.js.map rename priv/static/adminfe/static/js/{chunk-18e1.7f9c377c.js => chunk-1f27.d3c35fbc.js} (83%) create mode 100644 priv/static/adminfe/static/js/chunk-1f27.d3c35fbc.js.map delete mode 100644 priv/static/adminfe/static/js/chunk-2325.154a537b.js rename priv/static/adminfe/static/js/{chunk-0e18.208cd826.js => chunk-3d1c.20303ef7.js} (96%) create mode 100644 priv/static/adminfe/static/js/chunk-3d1c.20303ef7.js.map create mode 100644 priv/static/adminfe/static/js/chunk-5913.1d21a547.js create mode 100644 priv/static/adminfe/static/js/chunk-5913.1d21a547.js.map rename priv/static/adminfe/static/js/{chunk-1fbf.616fb309.js => chunk-598f.dd8089ce.js} (99%) create mode 100644 priv/static/adminfe/static/js/chunk-598f.dd8089ce.js.map delete mode 100644 priv/static/adminfe/static/js/chunk-5e57.7313703a.js create mode 100644 priv/static/adminfe/static/js/chunk-6292.0e668979.js create mode 100644 priv/static/adminfe/static/js/chunk-6292.0e668979.js.map create mode 100644 priv/static/adminfe/static/js/chunk-7c6b.c306c730.js create mode 100644 priv/static/adminfe/static/js/chunk-7c6b.c306c730.js.map create mode 100644 priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js.map delete mode 100644 priv/static/adminfe/static/js/chunk-8b70.46525646.js create mode 100644 priv/static/adminfe/static/js/chunk-df62.6c5105a6.js create mode 100644 priv/static/adminfe/static/js/chunk-df62.6c5105a6.js.map delete mode 100644 priv/static/adminfe/static/js/chunk-e547.d57d1b91.js rename priv/static/adminfe/static/js/{chunk-elementUI.1911151b.js => chunk-elementUI.708d6b68.js} (99%) create mode 100644 priv/static/adminfe/static/js/chunk-elementUI.708d6b68.js.map create mode 100644 priv/static/adminfe/static/js/chunk-libs.14514767.js create mode 100644 priv/static/adminfe/static/js/chunk-libs.14514767.js.map delete mode 100644 priv/static/adminfe/static/js/chunk-libs.fb0b7f4a.js create mode 100644 priv/static/adminfe/static/js/oAJy.840fb1c2.js create mode 100644 priv/static/adminfe/static/js/oAJy.840fb1c2.js.map create mode 100644 priv/static/adminfe/static/js/runtime.e85850af.js create mode 100644 priv/static/adminfe/static/js/runtime.e85850af.js.map delete mode 100644 priv/static/adminfe/static/js/runtime.f40c8ec4.js diff --git a/priv/static/adminfe/app.34fc670f.css b/priv/static/adminfe/app.40438ff5.css similarity index 92% rename from priv/static/adminfe/app.34fc670f.css rename to priv/static/adminfe/app.40438ff5.css index 136aa8bb169c25e0b8d589fba77f046107febb84..b82fcc39e855a2a8b6907b9c8ffd69ea0651eab3 100644 GIT binary patch delta 199 zcmeB7=}g(MMv)`Q)YvrH)I4$W7DXon=bz$C1ZTdICxY`qNe{tM&=j96pvXVjM_C>r zSgh=Z;2czTL~s-|B_=DWbaBD#jIExmp%gNiOVt3OX1r zSgh=Z;2czTL~s-|B_=DWbaBD#jIExmp%gNiOVt3OX1Z*pI{cOhF@89jEnY0dw!Z^b*A;kL^=Nc|urPz&1?N5fn+4LGkn8+C=c~CgTR^cXm z++hC4%{E%c6M1c(v`;r-_oP*L5OAW?;pkrr$ve{}HGt7gS7M(hE}2C)w#*}By>QZ$ zXzs$G&Ct9XNM#{@j#1_4F!ltFlRiF4 z4A!-z|EZu48entkS>%3xn2f-!5>00YV%uR5JuTY7o%3;a%>p)q3V68fWdA*Fh8U`OJi!GdLTiGFY$aX;rBs;Z5wsYZ7jnMX-!Ady^DOA zgM%l~j)#t2ibGM@t~oBRRQ>9L-5r!m9%}pO*yP33$X__Jjo5U($WK7d6%Dc}t!2t|OI&D(h zn~Iv_^YeY@k9gZM&cQ~?V(L#p%yWrZPQ_1xB?iv`lKCni0sgfITe^B;5=epbGT|aa z<|)OJ-h!EbbEp4&jxM||c*!K=Il`-wrD& zj+xvcKWg~LIm;C8JO??>D2h{FkuOR$=w(cFwVCQ}oH!`g3so)A?O!g+Z{Fd~Rypxj zRhpI?HqgZFT4nc3XY&g?o2JgziGOL+Yz!`!oEN3Lhb3zB1||DVQKQSJ! zV|5Volne9;P8UJqM;R7tmV*_Sl4r=2K$A(QwQFEiIrp+Z^G+UbC??t=$LqThRL=&v zt)sg46=s(PVwo~RzZaLL;h30x?@73mo<*_6!$o_JZk&y&wpB)IrVd zfSYC$@dh?XedfylGpbphaEInrc+d>SR&oY<4%W%J7IfDO&vbIv-Fg`wTE6s|EB}AP z8_!}vWhK0?QfM5m&Gx<=YXV{F8gC{@oZI5Rihv^b_w z*s0{Ya@3hC|JpPf*eypojULU7y@6jqe%$IIJow{C^U7w^K`oGHRrw=&)On)>b_Vpj G@%axmH?Iu< literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/chunk-1a7d.38eb00cf.css b/priv/static/adminfe/chunk-1a7d.38eb00cf.css new file mode 100644 index 0000000000000000000000000000000000000000..cbf59cfb567a8c2a9d315533d7146d905da471a6 GIT binary patch literal 480 zcmZvZOKyWO5QeYPO?MqD5JjrUX&mE%TiY|Thd@e=Af>wh^!hs}tYtxQw%bX9(NXX(5S-bcLHg!$Y%SoQuAc$T6y2UT6!j{1zHL{uV4P*FVD@jCjbBd literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/chunk-18e1.6aaab273.css b/priv/static/adminfe/chunk-1f27.c0efd1fc.css similarity index 100% rename from priv/static/adminfe/chunk-18e1.6aaab273.css rename to priv/static/adminfe/chunk-1f27.c0efd1fc.css diff --git a/priv/static/adminfe/chunk-2325.0d22684d.css b/priv/static/adminfe/chunk-2325.0d22684d.css deleted file mode 100644 index bdb7387006581053fe797fbda2db974e5eb7f4c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4748 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 diff --git a/priv/static/adminfe/chunk-e547.e4b6230b.css b/priv/static/adminfe/chunk-e547.e4b6230b.css deleted file mode 100644 index f740543a0ae4961dea98604533843ffc08f9f480..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3304 zcmds3+lt#T5d9THS?EG#Y-cyg$}jzovMjPJJ8EpnNOCR>`S*@wJC37dd)qCg1Om}W zlewI8WMhz-BtMV^7F$8VUBF^YMn=PLYTb`R0o;^m*?)bT8IVZu#nhTV(4W|rs z=EZ#3?Ct|1axjwJ)EGy}16V&vQSAdw6=Pz&IlKq=_lNLjLW!g3F0F|wA&5*GBWwH! zu^mG~4VOZrtc61{Wb*WoB#SI&&j-VH29b)F0#~ds=~-rJL-L%962~^p3r~njVF(vY z`95>5n~Ll)+OllT4Ft4HPiM78Ma6dKXZCk`b{REF)W4XX_Er}L69#K| z!%)V|7AkoRS%q>Xn_OH-yT(!| z5L06zC#UWQ;)c~4cNdQ?M+*$U9z7&bSCGU3LrAoen=3%T?)X4uB^CZKkLJmIo@UV7 zQpr~2P)27ciXx@0(r}5iM!r9xfNjJu)M};>P`8q0Pv~WIcMN+gp%j7y1(2$Cvw8EjO#E{+ z_Ns=XAO=MXMlISf1Y8^-I_BS_>LGe!0IULJ3Z%tlw}_%n#=570RSCy^x?*(wLr z3^6Srpa?!TvWe!PiVNT2z=sa&jpUA&lXyoxYN}TIA^Cb_QLINr3Rdy0S2#%~@m{_R z8v^5l*m-f=h3!F6{M zoRVsyRXJC%{{a=SfB|5Q!x}PLpwewEQoFvu6d3OJryWzRY}qU!-DBt_IUO~AD?6&# z-R{ccLA;1ka*NJ4oly&&`Z)l^!2K&uUMJ~|e|}$HE+NuMEB;=at`rEWe09q7Dh9nh zt+rf%>cb9NNxHt+#bMR=Cy@t-?!W9*vP&k)i73ad>eSRvK8`LP>XuTbuS}0&d$XH9 Iwu*544!JC~8UO$Q diff --git a/priv/static/adminfe/chunk-elementUI.e5cd8da6.css b/priv/static/adminfe/chunk-elementUI.f35d8ab1.css similarity index 100% rename from priv/static/adminfe/chunk-elementUI.e5cd8da6.css rename to priv/static/adminfe/chunk-elementUI.f35d8ab1.css diff --git a/priv/static/adminfe/chunk-libs.4e8c4664.css b/priv/static/adminfe/chunk-libs.00388c73.css similarity index 100% rename from priv/static/adminfe/chunk-libs.4e8c4664.css rename to priv/static/adminfe/chunk-libs.00388c73.css diff --git a/priv/static/adminfe/index.html b/priv/static/adminfe/index.html index c31247c03..ce53d8318 100644 --- a/priv/static/adminfe/index.html +++ b/priv/static/adminfe/index.html @@ -1 +1 @@ -Admin FE
\ No newline at end of file +Admin FE
\ No newline at end of file diff --git a/priv/static/adminfe/static/js/7zzA.e1ae1c94.js b/priv/static/adminfe/static/js/7zzA.e1ae1c94.js index 4387b832165fe39a626396494ee4962069f51ebf..526e228f59b19d4984b7336dd89c10f5b5caa51c 100644 GIT binary patch delta 50 zcmeyyw19a-8KV}LzP_?Taeir0a;k4)K|y9-dT5Z3t$9_Iqh6|EVya=XrHNivv0iRs F0RX8a5R(7^ delta 7 OcmZ3${EcZt86yA;Oaj9I diff --git a/priv/static/adminfe/static/js/7zzA.e1ae1c94.js.map b/priv/static/adminfe/static/js/7zzA.e1ae1c94.js.map new file mode 100644 index 0000000000000000000000000000000000000000..840e8a26be5fde3f8c660ba8cc8b85a38d9275c9 GIT binary patch literal 1913 zcmdT_ZBN@U5dJGBLcGnyW1BS5!H`J{E2y9`O=w!C$W7fgU212JQz)qaeRp<9tL{bY zbC<_pCQX@X6|`Q{pwyK~Wf`=-26wVwi1d4lF;<$C%`$mcG9w3>k*Q^w z8p!)_R>^>_dWL`XJ$ZE~`~MOUe4~L9QxC`?NS+Wt>BP3K>EHM zY9k{fg++LY9cSg{rqPvq#W&D4?}ad8ikcslG;{bbgdH~y1|%bkT%?%FNH{jC&>_{+ zLMy2($k+V|bY)d}rOj02*@JU0t*}{o0e zr=ln_HG(?{=I1=(v>UZw_BcIncMf_H6}-*qtE@4d)$*jrfJja7jP944<48bJ8w6xN~en)ei5vloUN8>fm7sPQRaa+71mL zokmUBCKNCZ`k=l!`|OOD5POSx;e1%%KYG0DkaH;GkzjKAg+~$(3LK#A*?%Bi5WB+LHmBjU`h( zAVZ_4Bo6jB!jSo&(gT@*smf)^`l2uM{ag!}1(s+1dKpa0lT@T**>)R3oB1EYVRC;P ze6lp`*W z+wgR{=XI)KdefEX#>FaDY>%j?wFZMwuRpTK8cdDZJmGpC2~4GIHkGVNx?G_}sUXK}P##tc-^f*IMUvLy?!#Nvg{8Uj@t-D;T#}HTA-pkD*`IP(BWtFCd~@ Wlmc!5 diff --git a/priv/static/adminfe/static/js/JEtC.f9ba4594.js.map b/priv/static/adminfe/static/js/JEtC.f9ba4594.js.map new file mode 100644 index 0000000000000000000000000000000000000000..633bbc5d634ce6a65e3922e8b7e6a15740db351a GIT binary patch literal 1903 zcmdT_TTk0C6#gs5lW1Wk(KPlz2SXt(r7$k*H1V)Zk(;<}y3~&Bq`(mWedpL|S}xPZ z}I0D|iTjV8|$j8cV=LW2M&9^<>t00Iz_Tp62I z%?l-kEJ1fUngJweTq-Y=p7T8WWm9M&Q!AJf>Lo+_dMpj5EwBNU;&`0pm^hB>D~QEy zp>%2D7%`ahqR8X~?ub_XAPm?b>}D4M>vwyzi;$fKLBIs)L-r*&4%l_j2NzI=tY@E> z_W5;9J_ng$suPCBfqkAZbQ#!upRFdenlmf2Z(zKFj93SQE}1#%;R_U*966nz++MBPzR+yGyZ9> z488H*i0^*b+x2FMWliT$$r3LJSiSG)@hOrHRFaA@ukw=IN0Ja^N{6%p;PF!4wA{?SX@QL8 z9woCJY}*14k%ZsA-<%JQp8+#SqB|R&=ewU&sffW;<-+(QJ`(v(t~l`1 z&$E#aqakhq#KVLqQ_;1fuJqj>!eRJc3_e^Lc4~%ic+b`cdTrwD9=PT=adr=8W;3E6 z$&+h>h8x}X|9UF8ng!Rytpi4$Y=cPF_vX-89`aSVHS}&UdS!SdBk6Awxm;gB_yCMn6bBA_=d z_5oTHC<+{)r$BGoi(VAy)j`qE)4hRyi~jy&&gYG!Y-O#)8>eSwS$sI3`8vj!<9$wU zT#Y7!=~ekEJU;LB-+VitPR_U1l>PeatJj6{`Ne#=@#)?_2!+N^$?FFcr(CmX#&xpz~{-|szb ze4_QFJlj|ll1}Phhd<>D#o3nYrZ`g1&w5W66i%&hR4C53CgD|XR_<+Fj|ScRs6U;Q z&Ic#?BJ)bVmM-SK(=cDW9EDe3Pv3R(m0TqkRH}9RlP}V05l$A}fB0(t{_J=<&iRU4 zOBHkP&c>7ZR(`lxoOd@judV=QtvsEbZdNOm%I5s?G@ly{wvuW5>8tbJVwj_7uifmF zE3I0t+G>?+mDWzP(JBW)aM)~=YxVlL8U*D|vzl|CwGU^dYOP(a)+lL~tF5S7sorXq z>z#I~TxrxV>p`>JX|#r|pk8j(E=xhHU2f8Ktx|5+1Nx}d8s&DanX5G`%3%R&G{!TW*%BbQ$PrSgN%~;)6(Q>xel-E zrB=C4pERge+NFRul~zvg8_c>{spjg;i?^Lx%O0!MawQ0Im68C>XpI_U0xcS=roC4G zEv;JX0s%mv102*%G)VAaPf%k*^`P9YG#r#G^opaXnM)mFJxZ{=vp3hS(bVeQMX)NGb3wdN&MU9LCyS_Sb?SEW^M1g&9E1!>Jz zpDAe6O0FhAFa}e#eyp3S!%kqM@v_QjhOtTu8q##yZdMIdZ#Fgi8q*e;u$Q1$y3{HI zEwUO^K^LG9rPb)OUZEU7vr_k^RtIBkQ4J7m31{@rpp7aRs)J!>*$z4%_L}v2xsz*G zz-C}%EU1clfKN>@%hgzK&@NT$Hmog){(w6)0|?uoTkqN+gKr?CUIA$}t*Qz#pp&59 zWL0!r0r6j+CTTC9&=Dy>VSreP3t z*twUs#XG!nUjtEVqwQ%d1_dmz+__|rw5!x*5Mw|hid+>+4T3%!9i%dWYLksy2Oyvb z7*y&dYOwke1HgemTZ4^Rx7q->(J-z=)0*CkVX*ySM08PYTn25{)ou?Ptf1QIYxj$! zMCtTcuES3ZfDP+0FrsY$kq$h{@UE>0L`4{ygJ#t6JgW&sLO!AcFxUi$w9q$tY=Sz$ z(y>w+=vhS8YWOb(aB(F16dPhP+QP7HrczDT!@vNSVOx&pm8x(ru?5JVX6&VQ(EMG>GxoD$hqvR-PlqhMxhWcD3ob5^YTo>CIqO(Z3>g9_rT-N{u2=W)t37Xq&u~vu`w#6P6!-Cld=nzfm zHTKw76VwZOgQS=T!lBbBA+V}db`jmf+^7!ic92hWPhE($3M=*BG#LEC)}(1LwOUT| zwB9-L2Y{fFsSwrIDSK3f1@jI4lf7vp zi57GSwq2_x34@YkB2wF}-Vn%WE!_z20;94oV&k=XRcuuZ3+&PhvQf+vVdCoeFHtwH zR7-AF8vcu~0#?+GVU%vfV(2{@*S?5Dm)opJJhWbya?z>6-#{GNqxd@Nkb7=`2oOaL zi2*>{mZH;PDSGc8)m#*6O(gzBKI#h5MAbR11B9gYW&OHG>5}kaD6UzqwW@%WjUn|0 zveOQzioR+vRQCniX|=`pTq$jN7k#lRypxV8G_nZMAXw2Rkfs5e8k$?xl!sQwks1n? z>6LDOv=NX-mT0XtQyu6+6#~D3P{xpL9m!OPhZU!@5iA8qyKcJvF+6m5mei6F~OP$XZV2>H54jnq*+_QT4htA z@EZ&1pi!~~TI@S4ixw&@yt^%))Raz#4&Yy*bE1yXs$FgEnmNfpZ=swTI=cE2kF5nT zX6x|)K>)YNH8944)uuCvpT0qxd-7TNAJ->SZ?67@l=)V9+qVd%EZl1;c-a?32SmRhx0a?32W5dj^j zTg%j|dZ$^kWvUhYb+^LMwQ{S{dTSG5udz(z2g@{7ybU;6B{OAOe2Ck!O7+;TOLb+D zC6^qn+Osvi(tv5@+S~Xc&9f2S%7yc>5xXtYOfK*JK1%xcHiU5a0blzIe zqMfEw&HbB3b&)ixL0w6QCc^w+2#k8;poS(3vuq;Xs*7Zb^>*9g5ut;!xo~Td4Jg`h z^&H)FBp$^)S+|J5twmT0&G6-Ly)qrP&A$;BoLEkr1?MJ&QtEtY2k`RRR|1 z(?H;wdFZ$vvA=CGel!nNKNAmdKTBH;1{U+j*kI$a3q2C_MXQA7k+7BKK@+4)!xkYo zAvz?J`;aL`k$+tSD1a}jQbU460IITZ9kD3u*T(j*V@j#Nm3dc_4D@7(V69ZD2X$%m z45@xxk#=0IX1z2zK(ba}Sc!zTTKGb1;mcf?*2MSs;qLss+73@Y8-IT{T9i&M#^ZT^ z7A~>*?5p+M-s{e*p0mGS3lFp7!{cK;~d3$a(Q zti(CxC#oRd+20jhB9L{XZXC1{R~U!Y0^xT8?M0o?UH@rHx{J(po--w&sK~$#gYUn+3cc6$Ew#vy@hW zBBV)QA~BlPKC436Ew|)QfyJ8kZ12roRvWYUN>$cHrA1vfc%?!~TU^B)d-@#9Aw)@| z-hn$O*R?eUByvAZ-B7^1Yt5kTZ<51 z(gWxiYG-^nVTP{2nQLW;3GgDiu76yXGr5no7DQ&O?_Ox)E zU1)}ePARgL`dHEclc0)Mfu%`1V;)WZR0B;!##c2MYqp?|0kwAIkN!B+u_l>stXy5R z5hLxU>@i%Rz`7!zAW|CU$$H1w^c2>c09gQLoB%g&1yjl%f_ebeU37a3!Z@tZXC*K^#bdA^p4L-7Ln+6pvM-akCJvKO+1&ALI07C}I z{-&)|bU9Q3!pFp)nCv5mCu7!D%ltMnyFI8nY1(sRts_PNQjiMTFw^ zilF5;3uNUt6chuNvGk#=Dr5|XP#(4UU~tf#_owZdr%UP!G-SJ(2>=3zW>GXYHTD_d z1n7$y;$aiAB|FV~E9Zff~5SC}&ax zDyWF>T~*A|WD^^V#-i6IoLD>Fa76>-fepyLss5WV2YUo#EgW_@OF&vsGo)eDgEYBQ z`OjD^WW5X3R;99IX*(W`zKM4|FeWK>B^E2Jxe3YHhf~kZNW8!9dB3<1+BORnr)x^t z73s2cf(<59AV%hXSM^j=NMgH)!K;!Z&Jem)%_jsJ$3I z`CKZ%B%Ck8LE6A`C7)g3`-!CFJOoi?x5~``a-_imSPB#~LU~09yJv8QIv|@H(*&GW z*#7R>y~l+^a~%3Khmc?$Sl+5?&-*rv1U$^k4M^w*Hv!6C1xFoDzfL#ZZ;NT3(I_*0s5Pk^2uE`Deos;WL|qp(I#8*`Oke7O1MSu_dwAVo%Gt5Cgy_%t|EI7nosqYvuwGJ_}vC4mgQP4Q}^PfK#M_3HQ zvy30!3O+kOaMMV!12mK}UT0$6?fNc&tf8b3GO2Cj!e}W7hDd-Vu#4n3#|ctKACz{$ z-hwXS67UVH#2!POSz~k+e3a655V-is6{tkpAjVX-xG3HNRhA||Aaw^h&}bn2(w%BU zGP3KGH|^Rk4vtohfSqQC9ZeM5&yG+~$8=BPYb~^irTO`4)|G3%i!kwP-X`{`W>Q`( zS}5;)<++KV9~Nv5v|Q0BagBVQ1a7b!sUk{!UydQ+Nc4Lci|h?ia5O~rEj z6GcG015ul^P7_-5U@f zmzC9Gn>UG`656P-je%dIqhU>d!&xLL4j==3$LJQUiX{`7)w&ca$LixPQ{8nWfxX{E zDF=7-)K-L4_88+;P5;)jAOQ^sM(8~NNo-0+MZ;cIf5TR6zPtSXb8W?w>Fg{mn)Us& zZ$z6!Y9F?xgIml)@hcI(*glXaJR%DZph_?9G<)D0Macb?8b?f*eIbhuU%i6cFxBWI zdS6ix0nJe67bJ)lk^jjaHvRMbaT>BX^vCR>B`Vx6&I;Ri$=AjDansb`9HT6)Z@& z3xX(>&+d9j1PMR&|r7^77$WY0uZh0OxKoWF&n0<=ovdwC}SId13Gaghx`i| zyEI{L1miG;fvb!UY%#%0NN52mbbNL-pe0$>R4kVf_OaN_2wk3hS zdeHOEZU3RVLYu|^9q=_VJlXEU-txX>rY8VnhX-<(bg-gjoG9F*3=oVlxt%phO%=Tj z|DtMWEd<+Oz?8L-?TWf%!=q|oc}PJQQah-NA}FySvWnuris(T;7K5t8+3;Sr+aLCX z15%Sfa-|A8tuPrfJ}g@W+eO%yZ6&bdp1@A&hza3VsO`vtsFAnAl5lrQ>uU;{b(t!b z_5xq+VU;%Ov~V8|o@ysy;x1-@1Mr&w;KLJ~#fOp$s_qL=Au} z)mWIAlVOvlz5`=$L~Q^T-ciX^xT8G}@zn(cz%?Iv7CH?#Ezv1!Md(MfvIe)#O2)Sz zIGUAYuPl?>XJw4@_F1vZ3_N18aHbZ(V3rEr+bRTRZGSc#YZ3GTkCXt92z;HA{D9~0 z#FIHR*`rdWNKYKQEhXTJ2SE=E9Ka6iY${}p|8TSmUA9FcRkWoBDN-$kUi@dYgDUJ> zR3`HCpkJ1!T`9E+*+;@3bZG%ZmZ~k&9K%}`>Tp&QbQjjRT?7^EcKlR68!JHcAm8I7lRWL#ICwhm$E3H7R z4td}^?GOPY*y6}fjM%?5DbbeS5UxyR>}Q)J?1*Kk1&cB-uRO%CA}ZnV6}2*FV5}nj zMG>|n1vZW^Lx=)ksVfzD7cx)yui@xsED<42;=b65Ni6VBH?RWeSJc`G+C5N**FhN6 zha&?wMG52JHz=i+YQ2({P5xJ>{_UsowSTt^u0d};Jf8Mu8E;Ztc)Q+Osr+7fT=bOW zam6F2V@IX|C~Anqgp?p77X>_U0J2*|lTEzAA|=rTmZAPatL#WIT-@V&sgRI8L&B)A zVv#gs^GL!fZOgq?2ht~6#;ltr=Ey#=LBzut#5gxuVw!>Wt2L#fducPU4y47PU|PR= z8I2(}XT4|!S_nHvul)qoHd=!kvo`uM$r7*g!x{Tgk_x>G5BD8_BKrN!K=G4zP)z|v zZvO}<(jspKO7v1o@=#p{N(7)ZP+&buocgUm*=sQlRswl>o%UEMw-AT2dWimz#m6$( z{p8ny%$fk-P!JM9iC*0_{m-)N(U-Jf^Y0tS^ARN`MNSz_`3t*|eo$AYm_-o?C_$al zA25K$GgK3$5(Kst^U`EkshbS1P(Gw(p>#;wWnxHYg7&5v%ij-6K}n@Im^ql{S>8?s zMCBq-ehN%j`YoAdQb&~vrkq7MwRk(>Z&QIfrb^>I6rIY;fI^2c4(C$dha3rrE{If# z>C9FtiW<`gD<`cWy*nr_I+1>0=zq@}|LY6+sR=P7G zyWQ<4sI~@D^`PBteq+D8{W_K224LCVeAH_mDB2XOEU&SRu$HPxCI;aba?4>Y_-BcW zKmqn3*H;3RgylJ)n1OGWv)F_28?DT>lIKeD7lpH)X#=j`)x3fZ2G2+!)0;Lao=7hG{=xoC}$Ys!$!i~_7dl?N5 zg9*ylCt2UN5}BmpmQ0DIiUHY_%<*pw60bB?ug1q5qlyh8Vq*{{uNQDOxrQ)33ARdO zmrgGB%L?GO>^mDj&UH+=H;$M05(Gbj0eH_dQ9oSvVL zCZ}m%W>j{&Uib&)_eTS#)k5t5j_8ckh?;qlExTLh9HIwafkcvQ!?=^dVT8nAr?Jar z2+_C5hsGdrjwP%-RD5(X2#zyk{6**?bqQ4{{Tt$;pNoL@)#@KY7Dc$DmX1K}0MJbTNbmyLt<_z z#J${7_>q`GL&5Ww`2cyZzU_FI`-uC;yg>s&urMbUufHaeNWa(Aum){{bY&C7glB`Z zLG|8Vc!`h?LBXYylmsFkD|a;4;JlBWSdq8%Vst*vZu!1Dq72A1aWkW)pv zw{~|^DJ$|UyT5J>=+5@Hr6pQiO*;c>6;a4Xi|jILMEyk)&=piE@!4eiv0{-#wb^SB z$gCo3qE81rsMlMO?Wk{!9cuqC_Iw zxiBw;y`pO@U2B0%F}_20kI2dO8z5yP1Zl}8F+QanIqW(HmZgrjL5ou*O_IDK zGPd}_STJeqD3I0!NBE)$$cW+8s8liZR8X%0Z@?L9F)N*Ea*j_nA8G~11r+Zxlb)=P z9f-@~4pqgD8NX(sI&4#U0ui?*us3` znW%CQrqE2*neA(WMG^xTgmeJuv7lyW+d$5?jzVW@QAa*ihA;^%V3=^rr~)CZt*c`L zq9AP(ZAelL8;~yG()1*gAq<`IlnYLgM~Kb+wb`nQ&V`{hDnN#4p(~d;)519@&Psco zY*XlpI9bhRivWS?NYbJ(>K*++guK-zhP&|A%xMI>jw#VStF;E=V&VWYb!$WXs_1-o z*V&%d#?L;Ja&~-?(aZSy*;O)4Ar)a(FcTtDmW(V`z^YTh(g*;0Q|I{&>}VnuWzlhe zQG`?tovfE2fZU{V>5-$B>P{&Oa8fu7SRxz1aIH*KB|6Ymy)j0~)|p@4kZq>;kMCF# zfaCKFUPaq?&$N&Nvvz9E7s4Lz7;U$OM3{C2Ui=(=dCKk+b0BMe*Xk-)3(04Sf;u5CKRGNooKh<~CN9PjMkw_|M zK?}B_q%ft6DySenXYx%vlRn{gXd*6Rp>;QPFo+pQi-7y}@ItiM=l&y_Hv*A)+BFM+ z3VV>*AVwKZec-B<`^g-wja_MOa4y}!07%*E!m2o;u|y}?kp!&Lgfs~Pv~F9jke&f0 z@<2GMi+>BmbZ&sI8S}1KOj;%~NYfkwfT)F71V^!S@oZ2H+b|j>)msQMhheKjVl&Y! zImuvG1l@p~Ihu%Bi&L^55vMuJAaKpHx`SeXMM|H@1e+STim68tn?_@wJ~@<$RKo9L zkHD)YrV{IleQmux+7E2@XS6xXQBZu@jbX(~V_g<&g*#)L>ejQA& znE?#;GHW=U_BJ7I|oY!l$ap$XX(5Y`Yg zt=1tprb0G@71~z**s@qRi4E)u^{?rs2XH{qU!w^zd|MYKF4nA>J5GQC7cnWfY$<@2 z2Vv83b8K9~ZaS?9mQ2pDXk)J%+A}vB&ha4adGR9y8mY*38i9OIG)2320(xpSq!88X zvZ>@9ruVvZI9LMai~KE2kP1j*Sc1=ap&CItqTdw+vH3mPy3z#{vpmR0xQ3pXkaD5b z4VOnqLt}&Bnt&FqV^g)|{$LQxA!v5)F8K0KJNFMhSANxq3x8&lo~|t1tTHSDrQGefl0tBpaSh2l1N~Z&PP`l(Zg*ql64Fk+ez$SJCS@j{_4;He8@O3 zr%})w(V#D7TK1tGX=yIzfWnH@fjLl_XW?7c4LgHTm1jv73_c3YKw2Tj2^2uW(-_$* zmf~&lrm}}%Gkl13o012S(UwbS;7710CxbPP22VV&At0E+I@30j}QE&5Oe`jfdRQ6!AWBGaOsJqE)8 zLl)?%n^&M=YQEj2fEbj>Y2q-EvZCY?8v#Lvxx#cnlmBq5!)8MRCACz>8#9+|!F#Lp zE=9VLk2?Hn;>-{QA2G)bd{ZFNTO$`qN%Dl?%*>O^4@{lq4bzuMXtjIr23>@~A2+fr zF|p37EM#SOB2nB&^uA+>)!<9z(O*kuDm9Wj>v$p3o3{qM*sK4s-){Knvf??yvA6! z7QU1s_y28QOQXb(&HCNh>C?xL$DhfLc>6ZZLEpap>}-<>q>Ts@e>%vG2Bh;k3T|?n zk~}a{&1ItNCG>0OkwGz2tvq-;_ai`0s*mLreNZCf4hJChL zIvpjex`lUMeo%;&jpAx3J}N53TLpPBBDQB0X$(7s>Xe6qDXZYE+!Zz(btfwxWeKHQ z(~?4|Y4E^BE9^e;bm9`IqUxFLBqsv=1PzVkZk6#8$C#BdZ*w8&Jhj;!9Be{Yc4hQv zFP9gaqqNv1#JbCg=bF5BT8)ZoTF1JYi2(UQ@m^={~aU zRBBd zE+n4dG?HP~5KbzUh-%RI z5|;R@Lr(%BGa(&;bcmd7mQ z>!k_WjSUTyIIK^Rv~|70ohUdl4GB#aU2k53l(r;1U-9{0mhB6jDP;#J&`Knv-EM*u zb*WLk1fuNEfbpxO0%D{&8aGqfu#JC>mUb$FVKGS*h5@R;kB-$TQ#bM7l&iyVBOfT! zHy;OQ6JZGkHX`z}GBkV0%RtHcc%lg0utX6R=Ac21G7!U-(A2c2%>1|a6mg58#^pdX zoyq^!Fad_bX$ zub#A1_yqd)fLk3j)H%%Bs7t#-P%iQt$*KWZ`iok}=Y zpgN6)aw*N%NH3*JyqwA6?Om}Sj9ZrW^@U>cyK9Jj*x2WQ6VUF3g*uI ziF@P7*Nkl2YY%Y9)Ht{t(d^$AJ3(P$scJ@*HjefL_aX_Z1a z=21S5_6h=r1Mg_oAPu^N=50T+B-Shz#a58m;8Q!rz#w~~#@^t5Qh>s1)M~IId4DxMa7P+KpNLeDVRX{(1Pd+MfWrD<U))RF!Pe5h}v z!<~o_xTF?GxQz&C&vG=pdeTG$MzK-G1v)s-$x+~e)b469ME`5lxHE#yDYT2~VAtR+ z01s>siC}BU2_c4*`f11e-Dzy$OcSCt0V6qr^(YK7w5p%b=^cF>?Nj~gXo#hf)|IM8B#VQpgMkn1rm+h*}%GYG7@+U2OdcBy~f+ylEbX2obqFlD|AnxzN(s3MPSXb^4hWC0n06rTz9KB3rKmt`O39h%-28z9NKZuIu~>lvrYlJphwkrN(zDPsh?-^$Pn zaMIHNxL6pHwX;1TUeToOaJg8d(WuZgUL8AA3sclAc0)NpQs2rhb6cHhnYh%|s3J#2 z`hY*`l(w<7U~>fMMr)dBg-%T7 zmTeMgds*^c7=z1jpT~|^#vv{%^t>Tkh7^fQ`&QrKgRs?Q2fr~J&V3wmombFkauc$s z$N4AX3!6xqhLWT&5yl^jUgTZjuWq>0L237aGe>3ot^2d_Ne`wblbv8H4bsx)<)^np zaFw_e=Rr}C(R%Lg9eK7Lo_{9q$mzvs5az0BwELp82m}q)chV({4@n8;B&kk zs6tKH1Ztt;v($5*R6_l@3vn=trtwgcWJmB9T^zcDFLJ>Lcer8SYBcorG57S)1MG%% zaGZ;{k^8P?RhpMoR9kNBzB^%k`_tnOpNX)>y~*i?{jNcBb8=L+p0s3W{z18w(ZFd( z9DXoEKRyn!t7`Zc(3L<;LyivMDxWj{YMJ$Tr4gq1Sye{|6L^KJz+sMH;r&o|6gJxA zv?F8`d9GJs!6_I zW`Gim4_q{cy2+E>1w-Tl5{9(cpY}rWwdgTua=4a|8|`sr%Njyc@YT4xdyj+>ge5Ct z7g_wqye-PZA>4~JQ?3#auqUQqxjIx)E|=oL^y>Z(6m;X91gliy_FP(sgs;h3j1TLd zx+>uVj_vEB9H}pP&f7ce-WIoc;$Ld!ShrPC$kLPq#--d(jWyDb&CB61JJ)DF@iesz z%_W+Tp48AHQT|D8Z(AfUZTbxCrtD_SXdKZk5g-%)d`YGYhFgPHu4j^TsL6YK*gtFB`W7LhJkC#Ul0o~iCStPn?Ozz zpgXB5LRmC3gRNf}*<=L6bTT>f)(_$!Z_8E(!lWC${$WpoRTmnNdMxIM9z_qLH)R^C zp=}PhwCrBIOu{Ey4i_oh5QH$Q+y{24n{cDM&DD#h@2OU#;p*9D+?G>;{iQqobYhdA z&S3hwlN4=`i%NzJ%f^+ySsmJD6;%oM3gF1|t~ogBXmdZAMg^-5I2u-LTY)YmzKcUZ zrb86<4i}I3zLix%vz*&u>`*Lw%}q%uRb5M>W?~_f=@M}5WrKqXbUB>}Aom+$DBtzZ zYAekAruf}2)%r^DAEPjyb93_5G<&czD*Nm_J{ma9<4Fww%F1x5R(CLZnwQ`ik!`=i zBFxJphIr-%V%?DnJ@{u)5V2t^w5%MgN@GV>p?axaf*o0EuE%XX8p?@N%Oxr9r~q4~ zkBW%Jpv`K?hbpLI&)689X5jkLbyw&jCc09<`X4vREJ_u^{(|ilZcTD}tbE zl1GwP_STpKmu#>h<*9`u;X9SCq(gC7lb0ek@==vj(n8SC5KlS*74#9R`6t4tIPxqk z4pkGP(mS>XwGOfE@r4nccFsy=&q$;wlT;$YJ=<6?0%UrVUjhO+I>E^luy zYTVHPXU_)DZQgQ|o?0Tw*s3*R(>#&rK_7<-W6}ZlPSP3OD3yk8bh$cUu;-x=-ACTa zYe`EDAU8U^E*b0YI@9jEZ$6g+c5XlMFi$JvzUcGsCO?&wBCe3TRBx%uXwP>0oh6fT zc@e}1uEbp(l!|oeDlf$8wOX@*3& z(Rc!ubv_(By1Pq|#KAG78~yqb+(>tK&>iP}Bo458-7`5P1d-VBNFirqD4M9$5*%p^ z$gdFDJ?PAnGE5hCsvwGllRI1aSkV_vPoZJ8wX0Tuy5PxzP*P=M6E0w}Qd->?I>F}g z=Wmcv+UW8hSs1Q^vx7~Cdrzr9;z1;B`e&9!ki)>Kz3;(EJ%uP(o}B48N|c%5!AZv$ zWFi?IBi4~Q>M7`kqNN-g#Bt>}SUY=9e%k#^lJIOg3E!vptrdLsUF)Wi+OrCna7@-R zm!0C;N)ZH6CypfTYV(o*j;+}oD^>&gW9G4>YRMA`_|C<;QdMlgPh%YcwB`-I(WseEmyHP1g8lt3$oqh;$O&`jFur}R|$5p z@YN7gy@DHuIn=nA2Qk&uZz>^%%->_v)+4%94R@=1;Z|pBuHBu%@9ph<`kp9CZA-OaG<$`ruQgfus!(;UIkfz(dXT=BQi?hEr7%wxE`AGM!yANj~6tPX_ z+-$l@1%22HetX_PRuG4dFEXYg{Bj`Tp0(sev1WD+F@v}v-B_rdHso(0=jofT zKNC5RNApFR>FN7tCuEyMii!~u;ybVpJ6oYJ2?#N{ByM4bmz;q1jG#2#95aDPi?n*( z2Fye=9-CJwpYgahO&h4W00srOe>bl%5W~Ce_Trt!totZ|)U+yUnQxvNbtmL&@Gz zUlz_lf3RWPknZ`z9uwp)OJ2y!q$S(c5At;a1{k*1WIBYt_(gj_eH>``cLc~4ph=x^ zohCqY1KqK$s=h#|^&kqQOlkVIRQ^U_lPwfgt12$=X|Pof z$*toD0R%UpN5=|p1)DMwIHm0Yw@Pb%S${a#V15Wt2+$z@5xAwvt(GM>3)p&c`&;0K z>L4_@OZ?o0jUIA31r<}}-MQKG@Tbwoxmo->f$tv={*w8fz!&Y&pFiIA_q$0TTr9Xq zAY;1Cec4)$SQj1U?C;-p%ar|;N%x(?W$S+Omve!gO?$iaqgLsGlekMX*ZiOUI{WM7 zt5f^<>mq*0Jn|)ufN@fz929jrkt`O4MA@jaUF;v$6~=;2fpX_ROi;2cz?Y|BTCJ#0 zEVWJ%R)}HF1wwEN`y;QR)v@>XMKy{QP42G?_n+Nj85FHc8x8uBbK9O7Q6nF!|Lq!P zUZ+S=Q7LMTVx`D&yCNQUl1Vz-O9=iZkxAT zTTu(N^mp~4xoSZB#8z$2SwIm(tX|X`l^D=$h3NsMpaeD>&CSDDJ?+?PHATaR)}%Zu zeRj~HbwOO8X9T1z)LEsdVj~2Xz6bK9`y!e(E!L0YEuNF z;k878LC;zd!x%y`6S#dbZn3shunjg1bM~M=_<=>LbY5~0^uvf|5}=Dx-3)1xnreCu zdDsgv>t=gsgqj|8n_X(pix2-U5@*|jsc3HtJ_X6V# zHnDh~He*@Px^q9?h3RM0fRfP@flA(gku=LPN1xHh5mTshI9iHCwxE7{w7>HPFipO? z=ed>ebB6A#tG_R)$EH!I#kl(q$>4uolE2!FbqxO$m3W=w|Hof9@A3=TFE`tt`i1P@O?y2H=kujh z4PUfYcU5eLe}9|a`iWn;j;4|_=m}N9#hR^4QtcZ0RU3(QnWPQEVD<_Nix7cMwy0ur zC_f;Xq;~p}nAa|01ZJ$H?kXNdwrrJqJYYNc?&-~%!kO)Kg!|(9A+)Cvae-NujyVlr z0Yp1!MPyOG2UZ!DaE7-V+nSEL(`^pwDVp_%GdVP=i5;s;Oyv|;m<{J9W9qmcLlS0i z&-hgdC8!Tw;BKC9_o&y3$XRpL6rB^bG8(F?dscJ#>Rp#=?jP+n&Np0Ay11@#>qHb} zWKwhMA(?;z^Y)_{w@kplXLXvGn}FR-<0jyGt-A@3qH?FCk7JU5Nhwo`_z+zI4P5(sLWn#HL? zyqx4T>V1z zhad0ESBkn*a7sxlYr1oBG!ilgPGxc~ECepxBbWTM2r zn;*|=i;VB);NBsMNr=8gP`R)rR4!x}E<}Hw6xeULP&}-IHH-c*dsg0-o z#_1qSHB<%`!a+yWbTD07wysFFM}(T*5KcAkuFipzH77qQ9!qp*LJXXHj1VGZ%<#F2coO(K2!Y`E|ZE-srLmEq6mtPcjPrHUT&kQ6S=ztk> zuY=AKnku2o>!e+9^1*A?}2Y>Xvyt}ERYcpLD5x1Il#4;|Fw90%}1ltTXwEDm<|ydG%~ zK4idRAp_dzS#byGiYE~QxwX&$K^bsJauHe=(YlDR+MH!#espEZFB>lWRzvMTu^V1(@@A5^8xG&5X>7Fzz>JNLfg)e-+{pQjYjz{PAiv<3~ z<>SL|+>7biIhh2LsKw#pr~CFI{?P#6!hSzNLk_0>i!&P7WikHcn->=(^y}rU7ftA_ zb>HLJGtT!4*lWc{5c7-lh?TZy8_r?7%s{8ZLXKq1Dzl!bK*iVLA z|FG2Qc{uUq!TqZ%*Vp^d7m3|lk$%<7m)S3xsd@5C;Qr0o{?5MD_QwT$v5rk7#lG<8 z>GQw}NBwCufyvK16IYhLXva6Oi+(h0lr-+kl{;^Z z_UaLVQu_4fjc;x?o)s&7#1|@S#p=3W9`&X6+pDS?r8)X?WqVrf^TCNPy5D=+a7C8G zldz?^5>Vy2aU* zk3K|59=>_$ATwX|X1-qk*||eJ`e!s$D|8q$mDCrSMy~bS?=Sj7`}s*LM9=-kfasKAP$;G6v%a?Mqjj(X7Ex*_r z@%UgCE-q%1++<@>xQQ$2&GqPH zgDuD2_$3x&F`r4(>PPG?t#8GJw`yH~l&>KkIjw!6>J3Q};jWBJ_pwtstjJ<;*FO4p z9Pw)N!j*kEbDuiIQEl5RR}jBPqqCb@(1qH~Z3T?c?_Brtq(~{yFNWz+RS|eRAw~7q zRhGvAj|J)uS+wNrk%|*d$yfAqu%XOLqQtDI7dHXx+>a5RM7fK8f4CTYA_$vN#;Y`nNps9{Pw4Ve4$Y6TZMU{cwrSDH=Dk~{Pg}as$NfeXJI%0==?m- zO2#(K&fq?823u~6Z;Z>m!p21!mYPwxwHS`(|W0~ zf_U7Ub+4r(goExE({itT8Zrm}W}kW&^L*jgU%&X`{%tRdSEB{!TRfVKAR^||{UW$2 z4#LY(A8-!B`J2TQ^&pb!-MF8qME&POgybBNmAuwBdv%8Dba9ryDV|+8bqkmsJpbk! znDzd%$4|a~^fJXp3)cuFw=Te=Wo>=2Tmn~)sw~fa3pgilT?Y>}W5n+=SU`=kR!rdi?n4$;+3|Umoo~|7NM* zu&fs4^NaaV`ceuBy}`irqTOlMZL|!@Oz+WzPQ^p^4u77&LoSV%o)(H%D*WY1=VuC! zw>%5o>75;4%udDl&u7zfvAFpo2;mZ*vv_|VcE6rZ$6;>*lQ`*Jj2Ff*9A>u1qy8IT z>#5fU<7#4nH>~HqG4T6e&yN{3&6P|#KdKw7LCu2`rBiUYjyL(1S)+ixz3N~C2f$)FyFO)A~1n6CmOPjFvS>1 zu)ywcNl5wOVsYNx+`PKFDqq#g)7j}}m9yQOHu%+Ouo!mpIJ}C(aCACc*t4IWoUDle zLjLUO2nZMH4@qm_YJRyZ6ny7=bg4}^MwyJ1s-#3osl7veJ7j|MO6L?Q&b2Qs4N$GE zWsV{u4?1n9I}kJFfA2W_J_mP()Va$(sM^hzioSeoB18Q+^&J)_jk8&+{_frG>3T3- z??@DEx604RkY*Y1OPBaal+P)E+kfUP+jW&|x}rxp406HX1r!Fje@vfvzxc^#vhQnj zp_rV`YUw|F$(08;H-*>ym(d;awJ>Zq2X#n7Td7cZ@P0*wz)%X`B}&A*t?O7@XCKEq zyZb)UEnv`C7pN?Q?&U^dD^9z3`I^$E5+>elWd4mCH`kp*)#mE@@mEEyA zZpwlrwOj{J72IPj^ab#1D-If?W_w(ucm=tDI+`bq$RAih$n&@muh-g-9y#&8rKx#vdd+)pX zW46zmjC?d@ge@uT+3Z&*%bvBpSTK$yizoe$c8T?qZ-iXO+8Oj?4tBJ{!M?Yhld!OZ zt)qxn75AmC)N1cfAnPZl!|WFluhSbjl)O{N@tZ~H5mg4tg@?W{UDge6WCL!itM_9t7=uDz489nvtI|l4u2i}I{&p-xPP;Gns8~ugitow zn!Q@Q_U-dM0dw*2RsLW9!~ceC`hWhf|4M)V@Bh}G|2=>ITr?%kVw74UasvX!so?@xfwufJjjrW}@!92tZH-#^|D9j?5BE^y%KdOO-so*ME9~`u`RD)U|NS5S zmw);9|DCFEBhFGCHBznr^S}Ss|L~uDE#gaUs^x=!`CtEcD_T5s1nV&o;q89@U;pQS zW@SRJ!yP3+%awTispvoXqP+-*Hm!W(x!r|e{6^dScN@}T=MTHTDi{I-{B;qIyM>rs zZF}uSro|re=9%%rNM`rO-7hM!odJz_>%q}&Y&*ceii^=g>b#jCtFLj~hA2O2<5Zj0 zk;kCDMO2jQ-Mcq(h8K(jHN2#{iK3m?R|GQl0O&!=7K*b> z3(s3kfLQMmW;1C>BN*tjj2~*RcsU&na+T;~jfd#j3Ud_f64v-)>sibicebv*u?7w@ zFq(yLFGe%@hbl}WR@EfAUYL0op(4R*P8fcO*@tHf`(qZKblG<>z7WZHbc|nt3(wH7 zy7|e}oGeIfS&7}OSY#$4+Sg6->&(h`lHKg^v(^LW_sxbe?L_YiaWcdzEw-&(cSpz4 zTUUzX6}mna(*ka|0`{G?LE3uzRc^X!R@IJub%h6CuOMMpfvnh1_cEewIY-d>9C^o6 zL@8ED_eBx!o?3Rlj&KGtM(;)woCBt$n+|^M9d9vCqK%ew!pmvU<^U|CE_v^e@H)L9 zC^uM9oli#ZzP>npHW@wNhutRVPnDzEA)V2*~JdjMKXXt+3T9s{5ZoUUasd7cel)d@<{A50=56z z7j6N>Lo~iMhMO#+Qpyw&u2%4l-e6rveW8u(JC5)$gU)hP;od#^NuvrCVF@v6Yn}GS zSH1Uhz10-4BG`LorxlU8C*8c?im{z#CO<|{3Z2pXLb1mUm>w;^A_ zP;93>biH&bh^pVampsR6oEG4N17@1C5W>D)$Pm(*G|cpAp8Pg^2`!i-B2IPrjTmqfO_1mXI&h8l2eWVZx)xpHoAwPLz9_ruW>*j6}uvx)Y?3xRu;5G-D$#GT3zHk^;BK58I&f|$C2})tBq?cKK7%o zC-KaFibq_U$wz>+rlvtG-ie>4_skS-rF#cZLDNw&8#1wpQ>w<}6;&gpQzRP4^R35` z3Q_z)hU95Ym78Q^w$*!8dClA2tEjvbz!_%pI2Fi+-ex2+P@;x%uO7#a9 ze~M;g?G_KyU$-twi|+WVbdf3V2^P1;r~+)Rw-##9{RBA6idWq*gRvIIAV6j{MWa4G`9M_8xc|!gvkmEoJFCml1 zF6N6LPl~b3zkQp5Gvdri{87s~&xO>-jX{WCLDYrg@$IK}{?AL|%*NC9?!JvU0tqYY z4Z6$Ge1x!KndA0y(;gIcftu);gFPwYLYX|GJg~!J>5EC zw=mLWU;m$id-t5%4i`rJ@>THqVfu@LKycT@uZS;TI(yP1St?db$&J^9ECA;BhmXRU7GYa0ijwEhL%JG)2<2JLch4)Cr>t^_yZO_Bnk_vytO%VA*&@J<8qL=Nq4 zVRucGFxA^~P=2tOy}t%_8|rd~%n4uZzdt*kj%ASIJ($j3ZxkMUv9Z`fERD(&G^C9} zp*$cjocv(Ab8DY&&B~X(@kRJxY9PaOG|9IdkA~z9lMSCQPFW>O2XAZ^CRUMO=LXr- z8;{>#Yi`7O#KyK5+>za{zeZ1Nx~L|Yo)lcVGHzqojoYqin0ca2)2fjB(V3EA==Qtg z3UY5odPK7K(}N_4iFD^!=#x#YBuGK}*s138BpfHWsyWdtq(k3u4*=?I=gxU_;L?q5!8OdBMIT5BD8c!ADoE=J!&RHl9Q zP6xUQj1U(VKY>5bn6geW8#zYW3Wr?8YiC{*T=72lF zp)lM}$)YrWNH~#4&hpezK(}EkPCPN~)pQ7Tp}d6%0yt>bqFCCWNhlWJ!f@V$xJlrE z-~nO%`x9yLnzqa6`#UBr`M74f6Gst>(WHeZbB@?N+fZJg#dNnfU#J%)>_;wP>zM|lZRT3GvJ5nD2` zO7Cn6e%y||ikHwD{8*aY4;l`-(gL?;f9gH#b!U!+q8-LHe{w}$W73W{=9oe_48U!J z?8JS#Qrs{Qv;WQvg3X<34}$=^^{4k|zbu&sKi}CjKs;uwg2>@PziXV?3pRsgqNgkX z=MDCT0Rc-ngj1G;Gn+F;MAA#*7iSXk-=_CzvWA4Xn3ki0tZ!6=M)(0|Hhn9Sc=Bw* zaRa$sZyDLSMxF0a?m?&aVRSt74iU~1#>R~zpc*1_`@X#hXYv8tC)0Eif`aG~mk4%1 z-g0AZ(5)hK2vv0+UZj3gh>hk1b^iEbu^=`);#AYUdjZmBQg%fTB?@r#Eptg3NaWfP zqASsg- zY&Y6v6)JG?dsmz{Igt>QWDS2ixu7e7)@HNa42N9Atm9=)kdAe&S zeK1cICN-@$KPNN-(e$pqM?u1~RdNNUMF4oe`-+_0Lb}S6NgZbf=7}+82rPvUSZN_EiV~V&f5$TLY7X_T}+kmhWtt6cuKW}{(IWCIdMqW$O z1NO)O)kO(DANRT+D|Z={CSxi%olry#iAE!(8r~EY|BAs9@h|UoFy@@FK@jnyNvogl zpZ>HYqrOe}yVKLwW^F`vMdG+hpPQN^v)PaAoXjp%e2MI#iLzz10cO1k+PJIeeamj= zpY#S{$zEd<5~OslZ4}p%8oSnS!tlJ*8!Ib6_WF+|{qY4}a1-Nc;J7AUL|vL%>f(h` zI{=)5U`ak>7WF4wI^3_HB&h#!1@#`MN$4gFw|#6#fZwff5rri(n@Y|8lkvFnHZ6KBud6`icaPL*1dZ# z7pa_W+Y_1s2Z4a_@*y2L6yX!a;}8@nHDr=W=O%T64C6J9CRnu&j5$rqec3Vh;ta8Q ztIKG5edezlh1f1-&!-EE*htM`jV(m4*+awI*lxkR87jhb$aT18JEsBOm@r zPx)3x#D*^W`tec1+gMPVfvKINM5))L+2KE59q=0H*oiVCd)+VAP^_60(Joo{euZc= zm6qQ^e#%8)aFT_~Nw1lUAN+xW-VD^hvic70)H(1M7@dDwvqCibX?KEO6`0fL|u& z;shB2#5a2687v+2b?iM63$t*GTK=j5T(CaaT*ms?fLXfa>`}P&YQ-yK8`LC3cNP{M z+mIO*`E^m6%@WGTj-1V|3jQ%AThb)zxAde;0&MHUhevtuYQVaIb8l!#MgIa0@%kpp zG~479K%~65>8$Q|>$E?-;MZ~6$F0iRt|yD1#%NnN$x@ObdKd7~*dLWz`7J|z`(&}b zb`bYs{UBUVa|h74RaCj3aP0t_;g9v(R#C5TOGlg@dK>KB07088J=S61haaAEvVH9e z(w##R5xj^==={ul6EudLfqY$@hL*byeQjJjcfi--uy;Aa4qpK%#{v{BH$`dQ9a-=- zMUK|<(!eVe=m!4i(y{NP1gO$MCM1lgvoOx_mZ8p<-~7VK zdtl>q#vin5R7C|zuFWLw>Mk{vS#DcC{`IiQ)V!(6kW5oH9#P!@@<%SO+FM#)aB|EU zm$l35KY7l%`gnOSquFH^7|+=)G14o{4u>(VUnmI#{xbfAJfWc96OpZxu$o0=BW&D; z$e;SpzDuoiKb~G@smZL}T9fa$EYod+?r88Si~=ZgFc<|XA2Z!xWsBre)L99G_S$`0 zKYq%^7vh|27#ut~wOfr5#SH!C^#l3x`&bBO>vgZ4(V~F0!bva9dvD?E^gRnYmHzVi z4+l?P?kAhta+TR+aVrl0hC_UBEAU`1~86uWKWv?9o)_vs&sNfY>R?`69oi z6VJ2v8u!dIOMX^3f6ya5=S{RZ*@lBNBuU|6Dt{~&n)A!DL(*|oJb24-RqTENiYS#k z&AKQ&NR2JWvJ-J%I8PW?V|bUCO+~4HSw}h3jnrJ{R**rob`vXq z|Kkf?4s!0w2b2%3{POWz<)NIp@*yFjUfErAvH>$Z3qg9f5!T2!Kf|r6YrXp6Ibqc~ z-lsWts=z{e@mAcK)eo z$9mL+1i9kig5a(^cQ&_TBo}6(u4*C*}_v`Ci(vJx5U6`DBNWc<}pg6K8CkTxb zHH-OQxPAq9BIlOJL#Er+ohjLOcClrd-)7|94Lv-JE)K{?J2fnDKY@;6ahpJ@Fm)pr zDcEe(B1aSB2^_!z&da~9dqao1K! z!Ga9ouva%8JSfbuuM|-?UpLVVMTQIbx=0kOpv2luVXkzmT099iu9boP!^_?7yHNQD z7c-6>ZT8MboBSdi`a*Bh7zX;SiRonh9N}|zSvSx5c3q=@_lOjnJvJlTM)^XXmvXwb z@W3WeO(xJgo?V>djdC+mP!O8jVMb_jcy)^CRkw zM^p^Q?N1_UJB6g}Pa-Mq_z&AR?1jGxK?J@-9T`dO9Yx$fKMoG#%@PCa!zZ!uA%z95 zIQq|me?1(J(4e+rE>6bxy|doCBi%h%i1>Yqwc&Nlpa*y9zX5t4#pp@#vfWQ2Xg7tR z-8&%Y->?p7t^D3r~-$55p&NHW8@@6q=y4^Si?Y0n=$e)j#ko3(75sG93`)ila3 zXQ}ql(`UOFR4X$vs&Gr91^!x#brHDP#w&apIza3zP?t1~Jp3PJO|BC9RgpBi;=I@| zUKGaW8TH#0iQx5<-r&n=avY&{#G6-j;Dsuxi( zHMdz=UOMUBJT9b;du~+k_R;mELRpf&)GyNTN98Q2(JZq%W2_It|F*W~4=*@Tj`g&W zH#^CwVjuGHgS0=bmPK%jHF9NDBs%$ejrfM#1&2j};9|btCn@9iz+!PwJdbAdc`zxQ zUd+Lq&^Vg!M~ar+uW4x#rfPwtby!Acbrkp!JdYzh54OhKWCNbhKaFS0g*F^tIC9sK z8#mW*{t2p>J{*WDA~<@(KXgH6>7HFKAC2w;UPnIXpM!ijAU}JWWs@-tVik%fYt7z+ zg5i;&@Kc6{QW2f)*O6` zB!>_lNe*RP3h1Gd9Yw^uP8jEP>p-yrpt)aM@13ml=M8k#sfm)dPr8nAW2KEE7Ql>L z@JNTS>$uY@1}?Q&^z<^Kr-7GgQHi*cA0`OgIL?%5Csw=-7gUOZA!7*T`=(bh`9M$ zW8#;PvnKx*HsIrBH_7u)Li~9O;?F+;@s#KC4}X@}H9D z`AkKAeq(g<{wS(HA*qj;!R__AFup$CG;iD=|vXZhmNTl!AFtp$x*Q*eEq>0}n3a{AYGF=sLgsC|*`X*9XyJjVPe zoaiDD;^%)|^!69$9!q0gim! z@@T*{N%>+cGjyuW`Ni>gH0Mm%k^AKsK|0zD<-df-WjjMchc7OU%lvbdlMQ2asK-S$ zONINr@flgnS-6q2GQDD*T%@|Pl392)17b&@ebndmt<%_h`Lz7~^!fPL97O_Z>9sWNQU8cz6bu_}!cAAYncZu)0(uhXJR(@f&p{Z>bYg{InCqYH6aizO_L#Xd*k3}Lh7U#m!AL? zv$UmMa6V$24UV)3nfGk*44@{{BeKRJ7>?O2*kzM9R9VxFvpE6WnN@W8$K2SN>1^IR z36BP6N2&rLul7V}WV{&S{nR=6rBOVaGJqoPTo;~hJJ~%oe=|Bi;)pOoN}*DhL2Jkr zKp8_kT1<~DVr*5dTE2TRk^Q4FII_&H%q(N@9-u-8j!JxV-F2>dUbdXsZ_Vhy0C&`I z2Q900Qsr8AKta2zX~9{#bem5_c5~D!mNJ zX<90?H%nzNC8Q_DN!6Y!6LrJcGx&4<*?`;MkeHMH`_gye`;X3u^boElT#S0-82w-1 zmXBy;Wd%Mqm@FX^L16H09eSHAN(WHX$LE4j8Kc5E4D|-RbJT>W-~54ImLIv&@(!0O z@#AkC8Hpygq!@`WUGT#-D{7Hr)T0TEAw04R!?mfiyV2Fr$^hr;o_DY9ch+uudBUPs z-=P~_9LHiH5l1@*d%NWWoqG}AB~J!bmZX<=X<1=)_SFGD&Q$jIu!zs{U-3(`hX4F* z_Y7t>-3#UYjx(wT=H1o4<)Lj~{SBOUGaXeQ)>L!ywZ&@VwX>&8QyD+%>yMv;Gq=eWRd1x6C*&j;JQPPr9L82Gk^qbekw}i^#jROPA z>@k#Z#{=^5R-$9ip7PF~nZxf$o*E8l9IIXYuz)V$(a_P)8y=-(fXzusF?v56U78Z` zTEDTNYx!TrtV2b}rLD_p6A5Er{_h%e4;yXZ0TSsNrG^)8bJ)L3ptn|c6%ezX|TKi`2@iYB; zX*6-yrJC&5(#6<0sjsGqBDl+9n_hYw=Av#?;mKrhJ|#VGsohhjJWprkmm#;2{P`l} z*Ta$tsO27c&+jntG#_!Fsz9M$u@Qig4nWvfw9?s;2?>k}L2fFrR(ZhG ziOtshYy|W0ZVRq;Wy{UIj+tk%M{_8h>_}Rvzhs9U{W3j1LbzXOXWFN>-`fkoN5PnD zxL*`4#*Ki_WLTYi>%^ES4N26%-)-Kf%#sN1voew zuuvF>bef;jt`<3yoh10e{TPDho9?<9?lE5ATpwI;Z$(xfhRM$gS5B;z$f68Frlb)?c>6QL~rd2Ofe4mtPxq~z~r zBIGPlQVFrVKtkyr424$WtWwWHlv0{~5o4D;Yf?_Tae4=xL>K&^3Wbcx)f*{t_o_fF`OpQ%KnnYthG@H*3|@Ni{- zd{?|-i5X~>50mAjSL0#DxE$MxU3Keg6uN&=!nU1jo|DkJI{GbL{1`HQEsZQ4+Rx|~qy-u8XnqTE&W>ReQBS)Yr_mlV3F*lBd}H?Pu(?qVa4mu{piQ&$_O z;^}Fk3oGQRa2lKFYi@6Dd=&Y9(b}dqZgj1@Q#4=FqC)w5GRZ+i6Xe z#C*EtrCCt7yu*mfzL8R#DUrP+)pW^}TB#FTQ{8JLd2TgSs2v1xUnLS>pETO>sRt?Ojia9%SEQ%Rt{!rh&eiG2TT~a-k*PZ;G)t zr?+>|+;6LvQQmK>w5-41Rxhij-3Cr8`Qzkm8{Ie*xx+9>Y5V^g&yFCHkV)t#F~jBarw zYAWR^$;9(#E`6SJlu=C81Jab26Of~EmPLE&s3j^pisV980oKGrd(e;c;LzIOcdhL^ zbIe*cuHURGyRaJ-qr{?n_mZLNaCmaztPFm0%2BodeiH*QIsxi+pjFe2O8_GcDQ#pk!O27Pu-NcQfCRE) z6RevBO7a5eL=d4XIY*Os0u4Xxa$8gPI#b<^_b{!wNAKzD)_HzMc1b){kbBE=vbB;H zA6bHyXNHC@vP)XrI+LV|n@{-{yi#UlaXZRdTPF+s49ss^M>0r}Up<#)%w={)7vx=e zV=gD9H9F&~XFDs4+7|D|LTYDjO<&nfHhNGrgSEb?o2War}?0a`-yne=#1OF3G`pbxZmpA48e!bVXn(T!*ll( z^4k)D-U~vq*0U=mLg`suEkRq}ImQ`_-6Sy|BK8*12@DmtHS~8NEQ}_uk@y=OF?v1L ze*Cf7$Fcf_A4{+tb{9?3Nb&NmFqGIq7crQb#|53Pf zj>FlSg15(vWzV@PJ04URqnF1H9Xd08WC|%&zlXmbBa9a^ zlXdOr%_5GDU=G%wMA6mj&eu7p@GOwyA=b0zn%IKQiB2+rn8dx-h@GgJ$2@g$d~AGT zryeFo7wa%P=9=GB)zSnIAL26pvmPq2i25JM-jG zX7M}udAgssncEpgd!D!iXg=d?CH?=~v|Dvu4$tnt4+~&yvX^`$XVRgd?&N(2=wV~tTTWYkK~F9206JZPN+30%SE60Z9q9d@ zft?)1Jy@!}$hq%w+eh$AdtTAz{PpuBV2M4Hg>9*y?_-2+V(?4Zz`Hpb+y~&nmNOCQ z119WJ$0JwEcE3n2wWi~cAbmCW%J%*III1A7bJy|-jBv$qydfXpeFgi61Y2V#rMq;Y zyeGpc?=7i^z%WXya?99Bjr-~DTMYF^y|TDJJ!=4t7EM=s)O}B+Xom}}>TPd_k@$_o zAmiv~`M%TJbTjNmJivR~i$17ve7AKj!agM8hwRXa5KjjMYFKjwT6WA1uYrL37*Bxv zhEt^^HSi!zChZx-TU*~@c%Ko{+i~07A--kUpG&6_@Sp1GQ*tqc2r%Y@x9rf9&kB93 zc3aT%<#U94U%QD>#eCC)Tp>&LM5Hj+2w7y3;Z3n?a!ac>Fp#OzL}q$Ndat|E1Le3U zTVT8;kW`{0vPJ6U8eTb&9H&r-o2~H;R_s^U(j^oVt%OeM> zmElInKJHq5=(qPC=ziRJL$RBGJa?xf0>xKHQG3m2@P7jn|a-l(5^X+LmS)^52p^;DeZ{tl4T?jdTVom-O>r>IoZb9=ho|+#Qie8C3-J>G^4OX-Q0h3u8HYD;?GaCAW#D}AI`HJgJF0SETUNxZ&XkpbS zMAExC0F{o$pZj4kq0q`p^%G0Aj?AK^u<6m*NM$*G{LtY(f`GJ7r^2(qQ^&u0_}G>l z*4;46kz=P$9zS$?T(?TL=FhOi5hi_+g6-0Ie)B@_#dfvG|@+z^Q{DUKC3*S z16}A$)A{ni`F99_{+aaW9$X}MGr98ZZ`1K<(HehaEtuD(g1O-UYbyB}<$8n8I~TCn z#y(V@J)D&l2MpmOww`CqME=3h6^}4iS4b^2h5aOrK(uVMfnl(_nKDxkY5~^bBf3Hp z)MPOF1sd_yXc<96BGigL966-q#$1%(){_$55{f<~$pGdLCLPJ;!?pl413X{@{D??# z2e3TgJLnNm)%J}X7esQ9J1h^lPYz=NvwNNXxPJT9LA1OcoL7@k0}dy9#GzF$4#g+^ z!P2e*(NaPnTG~}0N_a24KcbLFJnzF+^d{*k6@euV27Sh^5E3#m6ml@#>=h*Z^`X&8 zNDlbmPEzitOWU~!LWzkyw=0Zrvm1&ML+ADYqrb5mNP|)=xH#c8G4~KuC(4F*nMd)j zuFFk0vkm#i-^i8iVg#UY!h_{q!LytI&+;C?6IJ~WwS?G5_PDzJn=PVw52I)r7j}iv zLIOeyyFw_c_;Z5~lquc-Y(wH63|B_NiE2#Dwt>Xo#_8}{KP1lY3W@UxNSyx%fW)?L zxqG%^tb@PJ?9cSi{>5Eq|6*eHFYaOXrB6ruaWHazAByvLy)qPy-Wyfs|J#3y?nXBr z%Rm00{)}day{aVN@8f>g#UnR#@xocb)37^HY$rTKvjq=jgPoz7-=hO0e7D}UxBClQ zInSA0;dv$j&ojHiGrDw!SG{`=Q3bL05G^Di+Ip<;IPUlgcYnIao^vJyNz#MDbu@xWjX0QB+*n|C@tdwmeyC@V(C=&jS7t5usa2eYb zE@KI}jQw4}Wj7(BcfmL{dAB+st9GEg?`!-7O5D2{rY`Y(D2nBJh zx^oKEJKhc0#uohk1P#FOcg`XPcuWdi_4~<@qosuDx3^Sr@gCW2HKgqHdVC)3@MGUF zOS0#K%!b`3t|nR7rs8NjJer$5Xx5kQVeBqf56)tDNtl6I%r3*82#%@YRZ|t4t+0R_ z0)yRN6Xx;FOpdPx@w&~zV zpv|?*gejDcWW4x@^yi%orfpv8@+C*-zK_`!@froxW)58d^2>s>TETZ$UFleuSO z4)+o2y^c?MyS`;8y|?)x@G>^)5NGTjjL;4!PaoTQs@7@sU{(m;6Jw8TJq%3XTr%I8 zsUweW&8+>+6s~r{oKuI#PL5BU`P%8jC%+MsI&ab5j?q2LZ>Z>9g7?FPi8K@2=739XQ|e?AUd#ekn3kp; zCAE#{vdQ3dva$1O3Gtd^JHPiS4zp)#4?os=d^_43l2?wp;#Hu#S3O>6;`JEE-mv{n zFUsQZo=p&5C|ZweU4`}trO%I^4v$;Z4TlUdR_y_hE{jD>xO))Z=}w&)M#%_ue3BJl z^l&OfYql+#ctd_8XPm&AssMNYi6vo?l}3pY@1V7Z*o5JbV*ZpMigyTsgON<9eyo0e z%o%hHG^5*yBw;u1$>QiaxQ~}d7>lB%TQ{EE+eIZik+G{v;h9XhBnrcvW9=H|2FRFf z76L{DO$ItK;|&3_2mj&WOvC_5Sbg0=VDNEY)Q7(-U~EgNLQuqtPo3^ZK-ot03lX{% zN_Pr^VTMlAdHt2$nHcfqDIPPINWTRw&V+@-oG{#X+_UKoS8sxpMf(F?m5($;efxvYQyg`mIoViPOqd$(VY{_ub8z=S z*-B7D$tK)0+m@M&0gIjCFEr9-!Ktk&md_S&C?uSbBF6`!!-lF6ORabCVW7BkR;Icw z1r0wAW7oL13ah9&LthBPmz^DY`0n~2xkPC73<<8XHI5gmM!|r9qM)&@T`Z=u^r~l zx@zC4&-q}wQ-v-Ep8V=7%MCnYC@@iLReHGXOU3zEotBT8o0~hi$1-tNbi*qvtrhI8 zcW5d6j3RrX?L6)6kkgi3kB*!^`6HL@N8#Y&K;{rU4hPr-W<+RuX%yrxJ4vJ75J?#*KNvl1zb>YfYNJ*?~)kj%u|yE%?De zHEa#5@VIksJ5ViYxx=NLbA~%$QCCQ%SK23tr8AC$LJpY}DQ0`riC`Z+%*I9HdJbFs zi@`eMVrIm3On5i8+mer{`RKu$Ysck})-H_gMBbxP(Sr}qktpus1MPJh+>tsfRmv=d zR2XdVVJYXPSl(aTgH;fFH>L{tHXg9Jicr!y;~cQ8E2Ppcro}+T<5eIptdS#EmO}kP z6t`rc8q>*$C%A0(K@JA0BM~}b$8ZUB(M~jvxWE`ExT-cF(5!fGU=8XtU($!0E)2^+ zy-xSVaG^5qg?hkhw)b5v2h|D&F;HdO&SZ~YTISI?z8 zp*?6F=6Bn<+8(eduDD&fDIW`E@bZx>@7R&|V3maKzn>gF8%FRMsDgO;dJotMXV(DM ze25QJAtt$mJE0^_#|JD(3CdZZqldh|_`zxjz06}KVKIvaDjm;6uU~Iw!8uMJs5Z`H z743|&QRJ`z%g27%RY|8dXmPw(S~;<%fy%}cA&P#Krd5Taxe%|=MT!})zQ`SROpE)S zR$J}M^;6uOACL;@vORnoXSWkkXrY1nm+tjxZ&iKO1tl819u%s&^KX?Ll_=I4P@Yz2 zyw`lI8K&p;63X1xo@?etUrOo5k*iMyw*OC{Z{Fe1z;MyF6ZXoRpEX7e}+nY zNvr0x^t|#Jp=eKo*QE_s94#u0BrsS#=3XKf#~v7Cvm$)pPIqf%u&To2@ZL~zRPF9a zfA*StSGwxybJWkO^o>ZQ9jMoF-4+WWu1T=@j5VpK=#U)u4^%~3B`AlZ|3i(zT2F_8 z`oh=%gEh>75J5j(Gyw|{if&@C8sazv)Di`i8>o&L7CS~tU{)3U%pBehRChX#nTEAOqDG&){xBN7Q9&@UH6Dl6KX&(<2}2@viFZk9`s~!TPg!k#|)) zmH4QWQN0S3a@TcQw3VpJsr+46NQf3yx6;sBz*opX72>@)ig`#SgVJp~Q1H=24k1Mn z5^%8Qd*YBpQAkd&EDcsoB6(FE|m-grp+--Z!>S)JZFEfXcD;*bSW!C+A!`9KG z?zKHS0b}w9VWSUqI2Sr(&Z(EDj$Opu@VLF4A8VBrHZSTsC&uSmP2`E8RC{eMly53sNXIG}twso#$Ed^pTuj9_v_j3qlS7%>%(iyT)Jz>6HU|ZqW60QBPQrPqh};-&Iep)a0(

zM2CRE2iRs>aL@x%wU3|!ZLA;=ryh@ey&bcAN098FzE)hPLqWO6A=KAKF;H1FNnk!7amJnQ4%H9DY5UVzTnx1yZd|C(VPH>$J&Wo*bl{um%>FNZd+3|#$1)?; z$N&3dS^n-L>A-O6OWD-E{Z@q=b_f8>o?1SFbYkWnF%bHu_Y+PhqXxr#afAPByx8*NVFzVx}m+UkNSa=OGdmi;qY1CF? zR#kuE@Sx|GO6c|6d!E|&F9$Q<{`MD$r-X~P)^aj@ZA3n}Qqpv;((B4j?a2|_i6_?1 z((^cw?R&5}q!=qyegpWttQEJCeoV?1@BMhA*xzk$y+^ z9t_D{e8Jrz7EB?DOQ4oOG|zczFRJdloXAG5m@|l{&ZcX_9OQH4jxm@J5gx^xV%}Oj z=+$K`0kW0kp>|?+4~d35I>v~GlM#Pv*r&Dnx+434h%b3tS1e>PQUiX8jybNtW-fFb zc&c$u5eUTeqY8#D*Ox|9UxeW^*LEg6+JdV~9vD3d^HQhPKL7zRx3^LlI)}?pY#RRO zaz0^k;}`dn!{4~L{6r60$2pkeU<4;(mu{(Sm;9=D+j2XdKA<^WPpD)2QO?5Qc>0$Q>g|MC@)%7Db9C2A>G3M09Ex=^W%@Rq5JA`QEHaa&ifdw`P)e7IxbHaXx{-ia7NF#Ua)x=%F6B#1a6t&0tpufNx|+|8l#1jij+C;X zuksbEg@8#fgaQWy7sOC;7?i7ET~TOM z1|=aiBj8H`Bu(dwIi9n5P%T|4m6xEp#asY7l?qvPr;z7EK3^W;Lmp}e*5^jDP_?q! z%T||0K%7h-WMmCwshtkS8*9a zMa9;W5$j2AmQqFanZK+t^@fSEj+bbHj!!aar9x0-b(SmR`ceSvHB@lD!mQ+3GG&dW zqUVfOvZgXWVpEx;fhtu)GYhmrcd8U;#TEIUD^9Y0@_C!DTxFJpo2$?T;KNLmGDZKK z2cX3uv-dT$aIDqqqj-ztanIJl`MQjnk}JWb?7SATnR_JxP*W@c_>Lr2Lk0E(rOY#Z z`2sjsD3w7SkRuBoflWeEq=ZU-99U++JC;lyW>_kxNzZ1pK>=LJiNvyyGN6{8KzmS~ z<)K167JyWxJZr2u3*9V%8f0gImB4G&Ll?w6L1|DR2W)M12xUQe@zcUA3z3Cui$I{y zWkkhUS(d3NjJ6jDy^Wxf1E(@&Te>+B{R;1uN@;|}E%KeOR>0n3-ao=jz`D!`W2h9U zleJSB$(LE`0aB1SjJ;f19?8))R*R^8X%?A*eq=-?O2%Ipkb5qI^98=-C0wy4a&(b2 zEgy};9+`FKQVX>VvfBXsvp(~I!YpAmlBb+1bXo2B($PHgnx%u3%;jgvov-Gtx=L0H zl=;vCZFjzh7po^?fnrSVc`QS3N3n;C)qX39nJ zyezU+9=4dvOSqII<=;S|BHWWMLQe(KqQ2?bWnd<$h2jPpX4#UVmQj|Rs0ZIO0j(90 zwZw>-K#6vmiX}i+$QDE(OJ!!FkO7L&8fK0H&^10(5H3JDQ9~v=O9k!?*`QF)0{miz z0&YHM4XA)vD4SOs@N;{Fs)2Xl5>m8r6c9jZEEeT-k8}WWAb~l6&S8%Gu2opbstwqH z)o7T*Vp8pwmO;acaKyUddQkvn!*1x=awhx1thmYx>F~R-%aG7FuBqCoBes}myr&~3 zUhhSiT|9g8q5CCxXn&p9Z)v~1GqL@gwp+HzPmo$b4akb+MSjZF(i*D)<~V^&Tg+#t z*}zOFrBs|QL!k=!iOjUie`#6EiGm}_TFy>XLE3!LN+5FB*|5O%pniNMMTIP9raFO~ zm?^T|pv@|a7RHOHlr4>fZMwZ}22!QHEd(i3S_-?Hp@X?Kk+V#mjRzDr0}7Oo-LmBZ zjT_IZ@K8jK6F1}`97B#)L^bJqQM;QWG|N3hJacQ6Dr1DXI9y6s3y7cysAMT-MMhOf z&)W__P19`HPN#?o)4~OZX&7e?0)f82RcWuQgmzLQF!bWmPpb#;^ zLHVYk>ZNiPsW(hn%hAyi1YcYFBAkmM=W`;pS)^1kjU45H5JVc{4&-ur$^)%(h6xpG z0YEv%FYc4EU1vVK##SJcSJPEXDOA*SxuDHQh0TD;|IlVgEK@8*%E7#qfhn%!1waPK zw1APte3kD=^7IBljS3J%n6?b^09XKL6z{YrW+0nukJxSn5|kISD#6^exyUXGvV}`W z!L~eN39SoVD@BHqkt|-;zDOmC1vqNCxK>7%1F?#TZ&`#71TuudEE^ZbNlV(n&s2yVsS;(YBr+NFm4j_cHd#~EXPRasm?IaGMlPzMTrGs3HGV$3b`Y$9 zMIzgl{(x#InhNT7fo)5X3D3a1t3q@KMQ{K>2x?`Jh`&fLU=h$~U&_u>&nP&+@ErIL z8khnpSIQ$&u?aIc7OFWq1bh)+%1o(yE`s6`ER{x^nR3-V+E=R!FtHd_mnIuwoP{9; zi1x53OlWwVh-gN;6x11OrVu56`+lA7u9gsMc0Y#y675?z9&1GbG;l9#dqmZN6F8? z`Rh8W&4mW!zPm5Uzgo@E@O*`tgmwCEYNKbBY%R98YA4(*X?ippHaB`Pn9*aV5c!Oi zR5X|rLzvl2OS9yLovoG^v+OvlrAh)W8e#~Sc(`z+O0}}o{eLIR51D6Rq5Z zEy+CxGWSgSb2q?~OV6d;_tob+l30L(T}7M03~MHvn*_&msP_=jvZWFfGmkXx{vf}= ztI;*U2c>bSW(zfVdR|+6_hY&^SalZN1JYx$I&Q)lN)8aSRH%Hxd4TDykInd0eu6r3(Lss6=BFLewe2S|tUjT*;(PaWSdlSifl2*p;Rw^>LQ6 zBy|F+O#S3@HL2I6c62{(6m;KY5r*nCaq1ZogLLCkSK4>llR^hpQO?52vZ(&tGgVb# zI+-l^%}+Uh)JB{Q=u19d8AmBdm;4+1e5v@Qata6LGznQ`EsB%VbO$ANuoCXV7ikG- z9eI{iYO}16IQM2*_0^OKh_Y6ZeJy3J3Z_w+O4&WHq_dUG_K@ zA>CZnNwsLQz$(RS#7wS4NnsXJ~YO zx(XpiElEChBBm8&1HlGJYWYIR*ap%!JBVsV-IInI6h%IR=VVGXWO8v>{%CbbhO%CO zb;yMXW7FVoCR6UqM{}%6t3jLsLCXEL6-GLHf3?MgB0V82yT9RAwT|*8$Kfo(8I!4L zsk-*yA?#-8iaNrwM7L=`ah2a}ma^9WC?@<^l9St!vo`ZgwnNoC7xGeTeW zdD|H=xJa8=nt(O3_WPzn>MeQ-0WFHEmN+40ZcKH@##bbTKP57_+7X^5p7O`$TYDt! zuIN_;Nt-y$uK|!=;Yo;n{ku22B$-t#pFHEKT8$rVm7md6`Lw(d=|1rnuktQjE z6hLBY#FoY_z7Xlb5Gt@gRx%KIpk%g)E<>k89C;~4D8uZ7JJkv!gtzjES!eCCJmvk0dSaVS>V`xBXNSFPL^%)1qpM>RTVlx?hDlP+xjnFuQwRaPLNqMb;EYw~jz4bd zGz8Hrl;zXRcfmwJ2&YYh#-**9%fhBUL~~&Rw3D_9c9a>_zlb0yje|x_3l0fE1K}P- zqnxkO0}e6mj{`xp!Yh?oO`4HJx9E$U@PyPMmqb?Rm)0`1ifmX14Wk9`B8M#;s4$mW zjPy_Vs&jokYnGs$Qjg{<)y0BZL*3v`ApAOXrxWA{6a6aG+7o{1SFkCr<#^5&-KtKm z!3qdul#wa1CI>LcID29>cb{1OTx)h!7vC&Ca8gL_`EcKve^2W@dsfjgPH7RGv&9KS zuyl1&vL$JfLUU_*VO0LoQS<{DUtTM-szGsZg;NPo1YHw~ z2Jrys5SR={HKJdINhAWJQ`s8!d=uL~L zpDfK3A=O2DMyDw1hKK=utW1{*zMno%m2F-&w|70s*_DOqJ7Z*I3UYFKdZEV@B(+@L zzke44x_h?Un_E#xnpoMd_xq2%>O?|x)lmzljxdglsR}uP)=PO(s41NX)P&tYUhHF9h>-+^S(ejM-egrwCyQ3fb;f_+JK8NzO-$Vx?d}=k%oC-yja!yFS2|+! ziBs=862(m?QHj|{V_(coN&(Ju37st~y@Z6LpYkM@FG8=(gm4ElMc%T(xj*f8ewEO{^mUVSm5$k7pnqF2^X~kr?DvJUJOD)y|>n2u|>WHf0L`OrW zbCb#g38nz*Fa!+iS7FWilwWd#rfy^c8?o=1X3c7Ib4Nvk;Nr21cgDqt1RkA!w7JEE z_p9fN+$NC;?@;PnQ>Rbzj1@1pXbPqCJkOfFFShrqN^Ez&F-hW*C9V=kRf&~jXTL_` zIZGr!@}d$?bRNaXdwAIr7xz7YJIcgOD@;C}Y4QBQ%Q!S!AyfjPUbr2=&6m;3bG7#3 zOslqn1@WQq5i9Ye8?w}q#9L~(hc8pAS9&nB%F)y#&d4)%`!$+65xELWnH$FVop0DD z2XO+8*sY+(T0KsrsW7o8s|=spqp2hMku8(IpGDGm^qfdPf&n=u(7j{AE!V|moY19C zxd$Seap`}qb)GQyy8f@H)bJDSR`c*&qtjX$P5qCl28>n9Pd|nD~&)KN6S7$JOLr`#Ikjc}~@4)NA`;<}TvWuQBTr54pD>{Ky=KUo_o5 zxzW@-39bCcBbH!@=0Lqvzu-R!yLk(XN>}E;oZ>M|o?Yb@#j;YuVwMm@DR_*m%~+>X z=0RyR^)QYvXv`uUjIDrp8WaxBxLXwX_tY@=_Bzo=bvXV6UZ{*)5k8M!6?V~4iyg!{ zEI)pMy*PrvO`Fk_UAK|*ON^%UR-h^G@GmSf*+RUtn-0PdyYL_vXe%9iQJP)?|EX1v!aEA-uj;T}nVdj<^ z=M47`;ZKa23t#=^o753*v#2T;c8Jw*R<*e|=Batsqz^nPrcQJ77c}SgkzI66opcY7 zh48*BAu*g!LGJ!FYisi0iF;j(Z=YhGg5wIvxIK+uXml1=f&3%(3mWtc!mbge9$9M5 z)RuxNSvi@9ASle`PNO4?p!!BLaL7WFM<5VtQN#z~iHJ&?5{*Dl|2okURSX?!h~l@~ z=keF#!RxPt#RY<8@HEiflp3vs6$adqyOVj5;J7Ur}vMC|rOSfyLxUZX}72)tW)G)d^;}5!6^-T>{txIfJnnZ zyA{w7{^_V@c}67cVrw;kF9b8IZC=~$uo#|az7X&qGuF#1FZaG~VVyky2?Xr6n9W5h zIu|j|QGc&5^$o7326lf9d|*hkizm&!XKKn`!cQF=+>s^&Sf=j`pdGMU8*LkGd$qyx zU#bV4mL@q^8;M(D%&W7DL9HFIgrp!4P0{Gj*#+o;)mvX0vEn1Mt)MZ~moL_7OjHS+1 zJgbz8Y4XTp`P9gKV+F+PG?we>fGM^f&a5=*^K>Q@imb)X-Ch%m#WsTy!usWWy6AKhX4 zm<59wt^hmra#VikY#W+T=0vmjrO^^$WG9#*XNiABTyu3JsEEa8q4B$ zO88cz*;qA7BIj{<>C_C>m|v)rf$pN_(G9KM#4~E!sF0Scmc&J7ejbR};$0)&od^yn zJ#3UnE2+&iXqMcV8Q>f%p&9(^ff&;cgt8?Abi$<@-g&MeJ4pNG!`f;sY2N6#!+<(# zF)*6M1c5J0OGYbAG8Lgzu1@P56-UCS>V~O*eYeVO66YJV7S=y()k$|`N$nbqCyT!b6|0rlHe4s5hO4+M)`Q5y~x z>+*ZRhNfk?&{DI)ZN}1|lxt-MAp|J+^w#`* z!k3U+t=OpxqHN4fE<+_JYnS$vc9Fq%h$CyT@h3LixX=IDaLg ziFl17q3Krwnqm$>@9h_vWRBg-*qp>26Cp$SQ6+VmmOIU<@QJ3#eB_V>H@4{P%W+X* zo~gC*l(VoF(}FxcM_&CSfMv;dn}GY+x$fsTb;p68=b^| zwH`$Am_0*?jTV@JS@o+fvkV+;dO!=tt^dR?#E5X>g#iddvF$RD@6fI z@CcFx`x6r&7F$cYnID4OL@b+0d;`=2?E!|uHE6AkfO4IEw5@&CmX-&tQjMrGZPh&P zO=z;t8_=P9O;kAYDA&Zhho;#$rwK@gIZl)lq^0Wd;bjAAGvZ}Cqsz0*IDWCE@!(ey zjdpu|Gi<57vIvyI7K2f7&%U9w^Yjmy8b`y+Hc#|pxju5vNSI@$ZbK&_t#iH=#6{X? z8_lMW!~4!=GlcByhcFnkDLpops*ga$3^~PD)i&uj#HsFt(F$JH~(pDNn}HL10Jbb3$ZHSb;^?YGP$_hFsI=`!)Q+`|H81Y1a|oPtI_gbdxxIBItiy38BNh^}#E(3s z05qa}7f~me%p+K#&9O1MEYT{nsAOP=$9KTlmrnvg0?Wqj6{dgQ&30|p)bT6c#=nRsU2Mu}it{k#@0-L(}RT((WklWuQgsLAa4-8a0~ zXy=0=Wf-J-M;H3*H`Lj-g^&`)B>`@XBmg9AW$1SgT2Le=J;9s+?k$A1BX41 zvzN3-Qv0_9_HLQ{({_qrSg>5gvj-W`@AfKTx9(`o792!#b!NHIVLq4b(7^U=tQqY{ zL-E&1O!H((2Y%PVHc>*(G9;aJsh<$Zo2w8@1mike^NZ$h-dE`hHJazx6G%3y`wljm zciTM!ButP`SNR)u9^PcjFi`pG26QvTLd9I~zmSm)-(j7Ix{oX&KnYEUlvV zN!3O!rG|sl*vO+P(@LfA)R#iLR9j(D!ezef#IO@C-aAq=;vO^0--tj;Xh;eJPWw%YlsBBCEV2}9MH)?s2b_Y2K)cq$qq=P+;!RQa^*mI>KxxoF+m2K{K8)7~AKjoame@oY0x4J>81jlcUIkpjWi z=pu?HPaAxWh$4g;BEryYsq+l!Sj$>9{)U*szE1?lc37Hg#^<+NZpsYq4AtkDZ3&D% zM_X?Z?izEC(AVw#g?RWl6>~o69+W~Ur0tXTOU*qy8z}iyy~!~Qpk)&0=GgrD*I<50 zc4m&2MyaYuY=28W)3(ggp&FvQ!=1pTK?5C9_kDDU5Yb4mOqLB(0ejdZNkYDJArM1+ z^#JfV8)4#}SB;yaI7X|;XwH4Ne+bLAR{DbGY~*eFMz^w zD5>ZjO7?L)e6SvNS*>$yl_CB<>=Pu$KVf6in)#YM*JEMQnhDH_eF|@+GbdKH|Hg|v zNYh^A1Z#HXqUnXGrrlnos}DUih30x{YC;kaX`m+SCv<%ea6~qj8Zc6bKlnlCbU?-G z^-qMX)fOJEuOE>Ut4CPn&X~nK(0t74Tu?2@JnbUKoSY0}V>Ene@eamCw}12M?Q4G) z2TKGvOl`b-W%HBw=uEGgYW>w`*023LlC!LcMpNC7e%!tOkrj_mCr4B3KY!}>PhVdD z^9!5Tf9yVTba5g+C{2-g`{%!M*=QrQ9!h3efAN`HH{J@fcvGV8>mRSb`3#5=pU zZhY_7jlU$)ydBZ48!v3!cu6WAZ$Z?({-V17#_u;idUf;TA9jEGworL@W1>X%$egJA z>`ykYy}kaztLrb^1RkLs5fIViIjoC7YuI6J#Vs19>a9O@pSpVMgXeF3^d>{TCl*EB z_pXMcj}CT5Q=6Z>(tZ6Gx3B%>_EU^ds`JpW$n|$y(<1-Lv1C^&G%o61z3#qlyz#>N z&p%UlJ+dxZfB*gN%g=_n zBLkz28y_k8-Cx}L_=VWYX!HH+8?XGK`{x(Czy66kAz2yuw4~us zA~lyVCraktYG@SJlk2lI3e)qh7rC%SYUU_@M_Z%r^KY+T`HtmqbL=y_`Ss~rOpPqP z`~9aKB05Z8imZ*?O!=}2TchE`w8jv#2yA^W1;tc_fm^`HE@`w3{^ROEkO21n~J{c7{OZ!vkHiO~)gN8Q(N-u~&+ z-4|cgFd+Y&p^FoWT)cYwM<2tk`)!AAU%AqK=EIGj-ss*0I0*xykdBAeL$|N}b>sDS zyKlVL{rMHy)S$y=3Hp9HBckpHPj&xrrTf-zAtW>fA5T~jZT#`Z#*JTw4S74F@HO1{ zfcJm;P50{i$=zc2`u8{9{0{U_);_m?cJFj zVV>{&*GKxtXnHwUzZr)(fibdP(;h!v+nV*SL3LvlBM@E)0&!tKm? zB9`C1{?}U{{@~UJR~Vv!^UC_~1&r>~zjmlc%eOxKu>0||>u)^AST%aJf1U0kT|iqL zhh}1;{N3k&N$+SJ@H=Cj_1CUWH$Uip@{}gcx?-Is!;9-b`AhfevlQ{!-gu6Ib>I3~ z_vb&f8Ga93rr!Yl_Lb+>U-&;!D|}_DH{O2X)(7vbKl{U5fBog=pWnOn;rGFW?t51D zqwBCW8tQ)VU4$Yegzg6)Z2tB;sy38ZZa;OCS&-=R%G=aNaq_Rfab@Givmo8(wQE)( z{eQu=&a1b;(Oka%r_JlX*|_ojWR2_BU)lWlsqVkM=zu_bVn{7Bb9O5bM$5F*L%OBkSDa+*TP-u#z zDb)ct>Z<|SRJ=1P{>IzgtAAwjH-GzYqRl^eFDZhpzxdqke|vYU?F%a*=E0VSF0H@$ ze)prR|M$vwq-QxGV;7!XoqWChAFp*k{0%9t{%8mRL_;un^_lKFKUu%}^2S>qY6h=f zXGmfsPrdEPji)MLSjpta~zmM<$ zY;qPX!tJL&>c0C|J~@1FKwp35ueYzf8R4q>_?z#p|KbgCpm+ZwG%~74|2D7xoUgY& zdae8Pvzwp1rgdkZy6?UwreW=ZJS>027R0SS`<3qN9|9mrFmL^7H~<10Pyg1v-M;o= z_rt5}KlnHPg7LA{3nHAly-mT5@BX#>%#FT+u?@@Z8?SA?`YPvqaS6Y9 zs}*)Iw}17TW;`}qx&6#b41fK~Z()f~EWJH7Fb8m}V)!;Eids)s#^1lfT^l$)9W= zjsXkvaPy7LD^II4X`wgtBU6 z%F@01L&Oc6AX&0(zVzJ2+w3KrK8hYa`{wPRN?ri8aAkXT?avQ_vzs}N%rL>e{~wp;8mTVZvwDnPL$?RUf#Dhr}vpTbu}XBMI( zv_kq{{i6F3Z0P$?we@F3nQs5?MPcYo&m5rZA|zyc{!K?MfWYmaybGjN8*81)ul!ah zZ_kd6sFUpB=*+8EyPw?bzV`<}xB1MU)_?pbc#*4zuj}vJxc$m^#9n@Vlg^uc3M*mb z<_}ryw?2M7Tv5McZLI(C$8hoWmwvqYgZH~{eNXJ|qwhjnt+Sr}iYz?+7Z{S0ot!xB zG9zCAdshTjwEq0Bwaog2sg#qR{0@7IkxGbu?kF%eQgP|s_y5!J0=Pb6V^SduAU8k$ z5dsADv#0OA{L+wHU3aic2^-s6McY`TIELcov7p}|C6b6l-f!N-?nK};*+9g{r0U52 zB$TduMNcnuhZ3ig4vjg1&rfw<{IL7%f52(6#L+E*fLW&rJ0EdIClD}+9dB*?_9aoM zmtPb{m>loGEu4D!dr(-&a+IO_;VYo3ll+vyxGD47z53nFD^Iz;gamYpF-iB?_t#%# zt$U4Y_vt_0{>eN3H8du1iB9PBpT=ZN;?kk|^hOG(b5cN|Pu}@&}p@PbP_L`|jRzH1*^Z%q)%4wHcXxOyNOzN7#FY3fnEjah- zH8w(&-c~WympRNs_QZWRwUQ7_?R3s;^L0QFedxRK=0^}Ith@-fyO!!OBo{L?-F&0d z;gz>Zj2>zM7vFjmRDQM_7`HX%TF~zvEfoh84Xy}S8dXJFDwmG+DEdc@?Oxn|J3>P% zD~%aVbV5mWi05rpRQ6#z1(kj1zy0>e%BR=puR6Q;3vgi}LxfM?X<~Jl)KzVJ6YdEP z7MGaF@Fv{J)edIBwPs@uHM5kxUQKoM@9!?0X1?bxoU}+a?Ae;1UgLtC2aFPt62?|m zYFOStp(Jt%-8uc}xf18l(BXHipBlG=>3ek>?gaM?YoGps=5?ZM#yZQ`;$uNaySM<&|JW9g2t?5@5#Szlmj zu2|((P()!@EtWbP-hgwQ^|0B7hPUc0Z5ErfnwGUYv++6H>a~}YS#|Dud(Il`xj}~< z$_($K&f4|@T~jRH8_>64n*AEBDGu>D)JUkZwsM3}snvfa&U)pPS*L2tAO$)8y4!WBxT(Yn^VdI;09M0yu=?z=mNF^GE}T8QR}S1VAfziut?qrM6Gs>6o~h)DLp4&0TSmQM=O+QXe&k`ax`) zdak!UwA!9k!8RAjf?oPmy&3w48& z8X_s7V(>5zwy_Kqg9ukhr6%K=YS2mE2+KXU+^o0E(>B-K4$C%%TQbO>UOVV6x>-u7 z9z;6Roj209DhRy=sRNi0_@9^E{w^-N*$ybQJ95(L7G+|Ls{QK3@Qbs&_d6eUQazf$ z6D-5|+8Te&CjoazR^?1$c?Pp%Bx$eF0B5$j>?ZvBY?a-Y%Whuw=B6LZ^Nw0EM!Lk! zXXSJ9xoFYoKlX(;jC%1y(YRzpz*~m0nT}pVJ>|G11}*m6;D%{5O;735JFPj=(Niv? zr{u)jLiggBYY1m8Tym?A61v$1Y+k~`ZWYC$1#OnKX z^Xe^+cJhyC?!PM)3Q-;x+wR8|mit##L9SW++?fMz`L@mAqE=xx!)F}kR*0!3-<#$= zv{aF^UIi<`Z6e<0p;?0YkOg0MIHvVMeB>n?Pxtr-Rs2?aCf+bUL5UV&9!l{Y zD!-vQ1^S^ViDd$+ST*tkjK4RX<3 z5#`yy_lPugFBMxcNcP zDA*wmDCMNr)z9+;-7J=8@sCO7EZ{XS-b6`s4-9Bp?j_}yJfl#iieMxM*m&`kS75no z)r_lN#bY)n(3%6FN@5kCg6`S66L;1k`B`6;(f73kEHs4_B*ddt$)~7#MPSYmUxP2! z3x-QC)CtRFGfz-L^}^Spa9Gv}is;#Qf;7Bn0s@;a>!AM@mL;u1Xa?(ojnG%Vh+|It zgbK745QG^6Y>LT+UueQ0s51bS2xEAk&yX#L*JJ&XuI|e@x`#J?2Ht$IP)W8N1R4R% z_Z}$H1E!E7dX9UK|8l`wm~Wns-B;jbg>zaG0Gq-&MFbVF-SZ+IQ1R2dcZZCv(<}EY zhKRW$Lv!cppkg}S@389XLXryNbG!`J0M;Cl)Nyr9tOI%cRe(u?Q9_Th3cU-Yi~bo* zzya~NMa@)fY9T>Y9yD{%sZ4+`+A4n7SwE~5Tl74-JVf8X&#Wk(LWF`-;4neB_!a2z z^a`>Q_do$WaY+jqD&PtfSDxlG7UD>lrb2F-&|hU7k@A;dZG6TH_Zo4B@}=yADyUYb z-C!ng5nikih_#AmPdwq~7>yi<61EBiRw#KKh?6}aQkFb3L$NHVs3@b>lok++9@0Tn zA%054rejDJ;h~KCb?Q>I*#f->>qU;l3WSF8ifg`^i84!+5W{W|zCi2*Mgu9p%WalG zQ{*pZ2qI^5KLI()FggZQD%eygJ|;cH$v7Da>t~Z;;U^UP)6GV94LB9@c{d-BBZ_D6 zUd<0~eQ};opzh@nhy}zIBAv59Da89xpcMTW+rnQwaT65puQ-iIY+{+3*Y*<4<}C!E z0?b5NYRn8?R^8u-?cqS3xm92wVgiU1!5~<=n$`-F1xs|n4+Lts8uO@CYth972{{O+ z8~8PLzOF@u6= zNJKS?k`zW`$j|{7hA9i%1n^=?;!GN)s;1kD8=)uVbVOZVk}b*{@mBO{yGlio2%g4D z%9OK{a;VSf%Q#ym0*B@tzV3hg)GNrZ6}hx5PN-;Vz=1VF6Y@$A1Q;CVo~8*1yXkVQd?MHHYzfk+*KjTVxq8R+ln+H{un zSeO7$rr|FLvx~%MqDn$Nl`H@><-tW{eAQ$%D)bKDEL8;0QuV7^YPg54%Kg9ox?Yf~ zZ~(3)`a)0*$iG6A5I@L$)2|}fBDKS6^jQ&|Rk_cEbZv1$!+w{LL$$7nF2H!8F?qO$ zJ&=QutA`5Mp%55}9y-iQ#H?nOf~ZjFa(-o|op+hQci-<+o=- zg{Z%TQZCq1w@<8ANQQfKRgJj1zz0Q;XM3mZ8xf4`t83IfBb*^eTG*zEyf)JoeaD5N zXH9EM4CO=UfW+k#Y6uoYU?2a+%&=!dN>VDzNJ0}V&AquiZVK{yN62=0dj38kq-+?H z2&wn&5i$>x&u37I*-hHc=$F6JzPLQoS_&>KFE!f-Q+BcTz=8AU&!^Al)2)?-1G!8l zbD+JpkP2j2{7~z{!IWq^wOCC-WA0$e>!IjG0wKXJMUhp^ifU<=eS^XZGR1_oC?Yrs z8isg!(@eXFTL40`F4`N&h$ZI~lPk)EAf}oKF<{Bi3sr>7tUT1GiWG5I5S5ll6*)*! zzpKb)QaA)C5=0NFgm76B^a(8|4yX!7*q4hY!5P_TxEG6ryarz(vags^9>#&xr;QLV zgott3?0Lc}pH+2;Z-jlII>idhGbR4n@=2_=2#+I(LPQ-Nu?h)$gDj>vimsS@1NUS@ zbhdsl^~EYIzFOY1l$2^O>_4(K=1V>8j)&R@FUw@@6c^G)Q(v5!pPiYjIx9BkNWp(7 zWU7ZB=Aw0bbw;LbJ>TXF{8w~^9>T}L7xS4ywpelr6I{Z_%KVFL1ksR16#O>FacH-*& z-LErWQ@qZimXnJO)mBA;KEPLg7m1ULR76O@38HK8BSlh`U^3c;DB!qaf2f4Cq8Z|q zBR437v;B1`P-2ts^wn}sBQ_S<)L27nY;g#_cIl{Vg=Mxzu3|Y`BOQjI6=*ULv74wC zRW5QE8Upv%ebd5GK(}&ff+bB^B%@MJ3mf4_`VG_gkw;mmx4*oSB^+g^v-+H9mMx0^ zGz+IgUSflS@D(QNK_YIB%^58kwNQ&r98-WaeRCTC4r06NP2YvQG9Rv0MFJ5rrsVDm274H#(NO(hr3 zJ99?P2_z~suVk&VIg7!lt)e8;?ZGJVm+I`RcAYe~rWjc0J|@_%g%u|8!d2+;V%++h zWrvYBB|GGXmJ zV%n_ue00;*;pW8u)e!9v!OxF08RVQs2}GpBEI_vnFCpwHV6jCNWYbD55p>DqY5So` zW;&`hj0b7zdCCz%Q-TB~iLOVk0&D;tV=)BvEcpR#k#xj+7Y5FcwaRxUS1wr1Ww{Q* zrNG+45j*RVF(AGf#bC#mFfHc(i|z_d;SR64z)AkMR&k^-H~NJP#$Nhx1pZ>GLz>^zmGP26=1$r(*L>Hr632m`J!TZ)?F znsn5W2UBDnQPCi^->Qi|jYgm779LOz4iP$Mra5CIhnx887)}-Hsjgk?r28M4aEScrV0>b7N^o zo~VH`8Mt$~8_^TeN<}e8v^JC65Sh~=_7MuQTqL@c0%LQ?md%Yxk0##WevA>pGzrNE zL1J%ejIzi!N)(o@PTI7H{G!@gQXDshz0yzFE&WK1;9D$-FR<@b5Mldc4YHx2JA24)CAt+b1v*OVtZ4)xOd0~2#Ac;6DeH`} zIN8&Yz0;?Q<7e0I6Uvw?kseV>u0nQ1na@p(QmaX%K`SMOQeHGc2dN@gnaE7Lv`a_D z;KfvQNWd|1#Xh@4oq6)@(ouv3I2xE_HRK5GSebBX)0qK4acJ)ATR?%a%7sE>OY%Rg y{0&#~SeKN)~tCMW6W`% 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 E0hSkb{{R30 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/app.90c455c5.js.map b/priv/static/adminfe/static/js/app.90c455c5.js.map new file mode 100644 index 0000000000000000000000000000000000000000..242ad185b85359e60f6499e2f86014718ff6c5eb GIT binary patch literal 354948 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

^}Az41G!oxspNf106?* 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 gK#PwWRJQJz&cgECw^! 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 diff --git a/priv/static/adminfe/static/js/chunk-0620.c765c190.js b/priv/static/adminfe/static/js/chunk-0620.c765c190.js index aa8ddedce52cf5acd97737791f9e1f2776d1d327..72077a5acd00017bf6927bcdf51267b6bfc97729 100644 GIT binary patch delta 56 zcmdm%`Yd(BHX{QreSKwx;{4L0 Ly{uxr+{6L^P2Uq7 delta 7 OcmaEsx-E6XHX{HLe*^yj diff --git a/priv/static/adminfe/static/js/chunk-0620.c765c190.js.map b/priv/static/adminfe/static/js/chunk-0620.c765c190.js.map new file mode 100644 index 0000000000000000000000000000000000000000..f39b8237f660c7dc73db624ff3f39f1ae3bdb5bb GIT binary patch literal 63567 zcmdsg3tJnAuHuj&j_YYrJj|xOcloo72tLcEr}!Gk z54+JLuz`FINAGdHmQ4wwH}UAa%la1r)d7EgF*wS{L8Yg?GgjzieR8lj*%4mhax^`a ziUMMr1da3ae%8?*RvojZ`Gn+6`aQX$az;V^;e0fnQm)6K9AEFV9xIN{$px18v&l3a zpSa82(;hED;m=xgoKG(LY%=XZ{99dX(gvoxD6yYg!*`>z+!f?mS6K=$dNCbmy}n-V zf(h&6@kq#*W)zBbfUiuEnF0~ug@Owx=W%bCv+L~qyietroQ^K~UF{V=iQ7&On*0>h z5H%|suYWl2jisf-V7+@nq$l~5*p4np+BhF%y&=#unw?#+$KFJGQQUzWj9@4XC4#u$ zS7HrpCj%1fy@T>`(Zg~7VnWS1IQV&e^+no#a*#e-J6K!a*m}Nxu#vWRw_p8oa4@UF ztM#4NPj}_M86Run-|=WX$ON1I2)YA9Y~BX5GDwVTPdCIQ6B^Nc>CpAS#O#IzQPa3F9AT07+8L`-&fg!bCMzi^&V%o{Zo!`*^vMF)4r z@O;$L05cP18+WJ`+0oG$3=xCMj)+Q6z0WxB^u*r+lirCc<`fD!$%b84gHkDfR46DJ z<|i+B<9xc7Q`HF?UtIti2uD!?zoEhXi>^pfJhIsPtNa97Y>o1FJ-8#aTri>ES6_DI zuLl0gVT6{G^S)U9bhOd?AlA^$`@KPLinxK>-UIen*SSOD=(_Xe+vDB|e2!?iC|5_U z(Rr(Laex!3zR0OJoaAG&a&mFxJDE%~DT7&FC~wE(j8LF*{UgLHT(S*R0iXOefI9a; zf;d9DVfcU5?-BG{{P{-KnTkhA4OrIcTrj>2^A7|z5GS2|0Q<>tk&?JTy=EBf=G_;8 zWYt6Bw&y>H6AXl#KbcF1;}2k-Oi?hefIG_85qmi72EgXt=c=**5!2vg7YFH zwk*Tf7QVMx_u>ftT0*%ApB(D;-u1fdvD-U7&f(caeMV!Lv9RZeEs^mEs?Zm?csr8N ze5AsdTpS<61StO_7dxGU0V5;}0S7u6g>&5Nt2|&RWWmuT!Yum`Ag2YF zAST(d0-26r#^Bg++7oQyFvR+f`y(zy93MT4#xR!7l>+z2gtt$ z2#IiGNce8w-$>K6xr2|ixtYFBn_IYQH`n=lvYKwX>#gGQEGW*3;@|3vJHAF6-FSGt zRrK&v^CdoiZpx2;q0`Ou7wuX~+InL{zt)>ieDfcHYnrah=cZua?4UqNAoefPr_F5? zJZrvAw?RYEa~oht;a1u<+BT$Q6D6R`NdFmk1;9^&&(Bh24JG%VDYw?8ybTOcQF%rt zuAvwOBuk6YKYJs(&0nN+GrhmAFto1?g)t&SQf*Gmd5Lusjf)u>#% zlzxPHY)=6;+ko|hphym8e z2cLTVgna%%G?ucZ(0Q|+?n)I(*Ilc0!83A88O07^@zUd#G%)3%EvRN_D{262hPwY+ zM5_GEgwpd>e6`b&N<)fx`+2G$pX2&j`XeB0YEQk@LI+gMPSuj7>2J#ZK#N}rX0LE} zGkqo3fIuB15x*PyFK}D*YTZaDfDK^=6?ik1@A?4qAEWf$PncKQx_NKJdGkhcL@ zWlg!SR~elW`X=t|;C^bdRaGa&y>)sRa%-y9P&b9+5~**eYoY*Y8c5CnwxRt5sA>Wg zqa+kl@rqDxvwvrS-TE|AK- zivrJ7RS31UO|ekvMZ*?#yA40cew!ISeiFNS4FYGhJ8(1-!A1p1y+GOL!yJ#|D}=)o*}e{`k;F)%&aI-FEY2 zt^GT^9C1)6?SJUs%k=eR^{skWYbMd4OGwXNpqD3W(u`=T|HHR1)P0hqw#05Lrg2s; zJ1l)BbtT*g@%PllU1)pf^*U0^**KE~65AH5r)^TRw1hzETd0xR3h_TRg?K_rc2v*R zn%pN*MigOafC18k=}gwszLxz~l=ToMpS?!JuN{Gj--EA{Lriu@;>D|>P*(>!Q zDsva~%O?o{0@7Z}r|KX)C`$CY`g!g$<#R<>EvwIrC{1CJIa&_X#Tyjr5iS7|pSavi z;aJ@zJFp5TV8&)T+(;j4UM_70nslsa(ej2cZph3TNqfjPL_Uh$L?AAM_9k7oAzM1J zcjPHbkS4dYWyL{1E3KjW%JSO#VAqklapOX5Eo!X~Mba@#PBohl2ADA5LghBV()2@A zp+Z~fRj6)5hc+Q>jOGNS%Hz3cF$s0C7rfwzLh96F%g!^oEqbZ8=Qu``E;mGXHEgPG z(@A_SO89_=BJ8I5P>|~g$t+NWcEr_FM)0AVxN*8h3+k=)Rz<{b*Fd=bX5&-+d4k(z zuy0qZa4FYzdQP}Qz~HB~^) zMIi}oW-mTPHZ^S{KVWwXuV}z#);3L%5X&_^*bmT+bvR~;ku_STUJ3Pq1}d%LlQev7 z7D)mZHWVDwF0GC@PptLxH;oq`)O>zZ%mm3}(Mt;o#99k971O-P>d|k*FB9nXupJZ{ zj)pAFVqZHBYzmrdF(~sSh8}6rOaoz&eELWj2FplE?=ly_07xZoDg;~pCEdKI33hC_q)E97 zh)!!&|5R+|OgR)H%r-uWh0dp`k_(NR|CEY3z!RL=P}2xOTw&-4L4xpe!PKLOF8q23EY-o_%%7ao(|aIzc8_dFE~2Y{IPyn+Hs-6R>G+6 zZP+c70)b=cCUK80rNS2FMcR;B5WXe6BW3bezVHSa?;vVpDK82IZK^r&$?;L2^KNV0 zeZY|ZJQdmnf5|r`1`|%;Oxkd|)E)#s0nKb*^)%L+U-kAgu$wMXa;*(F;Uy3-TSohq zOkdSX&CJrM4EHQ|h7ia#ojTGaLpcO_Fd_um^H6o@g=oZkRdiwWu`uLk>IFl}6VggL z?yEsPRgulA-0hZ)ml6DBdKCrcHW~7iU&;7uV|+0 z>2KyDNcNZ{0ck%Uo4VV$L(4)S6Q$yZW>n9#1p|PZfJy^Sp7o87tgaI`HrUoil!^Mq zx0}ioQogM2L)A*9Ww&vs1XQ_UhDH4lR)PXvBi`_ijGR19U`02mKN?^=rZ&N-02*U|=~s~3ky*uiC}OAD z!|zHXw3pZm;jl#grAovoq3(v5iw3|hLDjJUL~>33sY1dRQOzPp@`K1(J;H(oK#2p&nUT6L z_JD~k^oG&C^trSp4MT~5!E_rB6%n;b0UwA#dg&`X$0l!+@^o>`#*L`@pz@7fN2&BiO}mRwRdg1H4E zV*EK#DM=yRECFnBMuOaWCN>~+z(`5Rk_rOp0aA)B@tO1<_420a`!o4t*3|| z^m!|)8FGy#A}(_J-4EhME=;r7?yW*>BBvGo*x*b>Ees@9^c27n0Jj{HJzK#gdD?5q z{ls2@RpOGal;rr#3HVo;+TqM5O-Q2wia75I0r~*dFPDXsi@4#%i>_r^;bkE@Pq{Q8bzF-L-YcxR(8b1-&Nf+sJGeRF!me zf}yoCg$@f$rFf6z^Bx6{g)^M# zYldEM1GB|sh^6?!jj7&vuLK1*-mM{%eUiEx#C=6Ws)NoM3)SX=&UT7HGZ~=7Vg8%g zE=X2D=PF*2KE);`F{49hW=r(Oz2wLiHFXq>I714Ope10w$e z7(h~behv6F4a9BKlmnv~fU>lc+9(!jH;Kc<6dxOVjQB52Zqt%QVmyP;XGLz zA%b6m6Pz5SK7Ar>1T_qt2uA!hM6HH}Nqj5hqMNR(Bd20VVI%R??V|++VU19j`#hDs zy_EiGtKbGfU=E(pbw<_}TQj+%%N4rOL6#a2u2|LhrPw&l@jEl7>Z$HPE#@=68_Pv0Bnj-Us5LJUdis1(Tr{y zotGQ^s7oL{^-Yi&tGiFZhq%MFviyUlcBa;<>a>4}nVR>mrw_@j_4Ldp7)aXJ|9;ZI zDz4^>4E`!HZ=VXAj7;OY7#k$Rw8|4X2#9=0BL9>Oo?eSKbwYKaq!MbM5StfOjJ)NI zuxc9IX+)TcT&+32LmEY(yMreZeXR=H#+(&8Jx z4j`V*yNHqM!?}Jb1sNLYh`pHswzv|j2Uu2M70SOk=tU;VJjmkGHu9E-nmjlH83odn zb+CZ@KSU!Km0t)?@Uf2F6osCsa+a4>*^+4(vO;qAt*W82+Lj31Qf1CvLjd@8HC@u- zrZ^iwq(Qh9xD4G|*tU_10<$IFs^^DRYvhSK)sz*zxykPwR$xLvWDyavTT7=H!I7)7 z1fwUqRS_3vg;-?7i5;O9T|S5sq4GnaDpJ8#wGB>5_=hnW(r{(F(g~Czb@bH8w;}9g``bz-0z*y2!;$~yZ zNTHk-(@_9(E<=-=NNtT%=-@?KM^EtyslL4D%L5e`6 zRR#}LY!4N<&I`_{$3_5(e4A7tzDsIHG&vfg2C_f_*%Ad*DjjjQ%b9|rin$cRG30tc7CI zAi{XBq*;Dr%B@@%&AnU$>xCz1hm|vOh6$<6bo<$vNbH$(aV(z(Q0AGmp&O@7pNajN zSZwvcj9TOekysGEsvDEL8t%2-T&R|)cW}LIgE=Pn1x7;P>1UzA)+fjs$-Fb{<%xp< zwz`%Lm)WqY(pBd9L?Qqdt|-D6ZUz3Ga#0s+G^)jWXD+EvbZAu7zSgka955bi1Jo?t z(to>y?RwmjyOnkkhC}n?l-y@U4Q#zIZ$~Un)R`zU&Vv)N-_6z0hrL&=)TsjXpL)Gw zl{y$8>3o3T7OAg!8FN5BCL{k+osE>PT&sN);v~Rb!Ar>7CIP9VoD-%^*a%enLCydKS?34tGqGyv?j zDAZ7G`IO$dl1Jo}>8HnBVyFm) zjryM`x<7LNckCn56RugWpRQTbqJp!`QdP+ou%#h9u&TR+RDuGMEFlnVg{li>!X(!D zO1-l-FzeS~BJxnwZRM7+S?36RK|6h?62o*PRlLBfZJY72e=@#-rz5u0S9aHY!mREQ zZ%L0(!%u9%RQ1;eHp5`UQ_VxdB_IT2?C95lu4dX8v?{M0$1EhPW5=9&ao0_ND1*?@ zGM2UUcLieOTm8X_QpEdb&^v?T^bVtmvfeR`zdmAdFAmYUCPpE*RkW8P?Bo5H8RzA; z!3%X#E*<3f3)4PSVoXM{GvvE8c;wC`H`44YhBk-)5G0ia2e_ZNG@PUPe^y}rBEvZj&aWTNF%VoaoTGstt)lRB zuaRDdi71quHfV#sf-5o#5(}ddQzt1!h2n%LJ}Vx5f3^@Y_Eg=xrwQo&XX0GOwk3(9 z--%v-?JE#rSAqJ8?4Kk;JF$5{E+1-Ln=!+*vfK~r(qZY;r_iq&4jNf1mDvf2wh!f; z)TJq}Q=x0d0Wt(-dmGgHjV;K~6g5D{tOWoasl6%S{uZ#uV>UM6A*L39?6X^)0eJaNm@P?ql8c{5DzBzpEq(r8~yrlUc!deQ55=aX+wr_=KZj!Lnk zQ97f+()UtdDm+RKt(_dLk&S!5=LwE6;NcqIy}3O+AH2DpERK@a(xEhJkIpagsQl?P zdHeDrA73ULdD3oi$($3cF(YvhNEHfnr$a|@Hz*Bl9kpst$W%UGz(n0_jV%vKHX}s zKi^qb5Ctti;-TxoWs*)#&+=h5X(nqUJY^65w)>-tt`LU9GH?`0??etwNnYjT5c*C2 zGgG2zey0NmVvUaL7q==nn=tOmL*kBs<9yJVKqk@rSldz~e!VXWhG# zmH>H|jg!)8Gs$mU&3%YO60VQ z#15qp=DIUXlJ}>0BwZeLFM#WjI)J?NUvJ(_7XIMJ-rODh&=sk%3f9j7stKqs1M!N!;ub?<1t*$a~#D4BaC6{Ax4166NpB~ ziMB|-gQlpW%q9Q%pRUwjwN(93?YqP-{k>~Y;=xEIx_D$#fdMO&`^mzsoj?U??na-|RCS*);G_P#oK#5p-k~#ooNaZu-(VzxQ_VYr45|k2 z$Ah9q!>li^Rf_LExV!XqYkBEECV6MkSl~NtO-E{l^8y~aVAg1^lU`5TxWlV}c|Zr+ z>uDT@y@a?KT2D4X?-5C;|00-4Hpmm6Ktji?amr#J{c_3s`opn+0uRS(;l!sV@Wh`# z9?ReA4I_ST=2P|jJmmtuc5t46R_cbH+QVORoDG=7^DuBLnYBVE6I=9@B$}^B`XiVUQU*mAIbm8>)rNzi!G$pKQ)uk>p{-bgtm{9 z1G`7y$=%ld*0L7hRFM2+1duq)MSK0H>fj{#s3?Cz#G_J{=#mbTf5OcU&im3*03Nh( z>{32%xFFRKCd?-vSXl?^>Zh8{~r5Ed=wM}uvVA&MaI z`V>jIJuy}=;w;ykCke`%Ny-+^iiToO;aNe=C(wnO%ZQ=xj)LL>mNMC5|j zn;wUj9OaH8MlMtk%z_MJiRNxcu_ZZ9LUR_U3>Kat2r54uB_^7@E6}{35GMNr(Gs{X z;@c&f=ovay=4LC|!TCWry9NoPfZ~Bq(9>D6@DYz$6M#~1lw)A6(ysfaPOo_ka^<_@DFC8<8FO24A& zxtR=*i-T3!5bfY-x)(f$PnkjG^hzIVER7Kk+spcssb994qDbh9w2=K|G(T?srY}Fg9so0i4-s!Bp+Sj zr-c4XJPI%9Ovy`!j#{^CRhxJYvz{@4~Qo zLge6Lpx(OhIPeTOLQR|roSO5kM{=fC(wjoFX!B=q-Ph3NO#M3=_ce66x{+s$3G?y3 zkaigHhxvOi=pxJ+j^*%=Se?Eb!CpGZ_ux3-4spPnL|??5Q%rS;dcTL$M*yC1#sM~r z!3zS(2ZgDV3k|I@-x>{>6|?3X69cDm4F?&=V_w2fHItREmghBN5cUC+Enz1ue%O5m z`+~in!j3waOaPagjw)&aPk~b}PL%tT2o+3Ka6&+Fk=8LP4t_Jax4hi+sm`3~-`pd3 z*o&Mg5B05@MXX@h!c3Au&+!J_ zFKA%0Q{4D2WTAuIOzwU~ypuW8WnhNmF_)81mVpt5PCg-LqCTv@13z};RNlti5;FTd z8_Zc{lb_aCp4rp~xaKj5CDoQAMnyFocZ#ZF7C{DQ(@&9xoR7|#_EJZD7cI?Xv?ru} z-gCJclB6~hx~Zm%nwAKXVn$?~);h7=Kam2SCF=`}UH-R5bpMlPhSO#JZvt#XGP@{` z3RO{A4E`<`w=}>rPh|x3<@7Jm*>bVx9LC$wH_2ENhVF(9zr}~&!r6QPSd8ggjgVO=qWKPwR8^0_Mt)r9xGe$AKnd8bF8EL+cY=>QE7?SD3@Aba({QJc zjQj@AhJo(RDYQf2`oki=pA!Im>QQp3QLlsj$?IggxVvs zr`{{jHw)`yz58BugKklgN$P5Sn=FgtY?yvvsx(q1Q%C?aJJ(c(p@LAoD`X>QkeK!P zs9idXfS$^1kXV$)kgDSNR^B-|jukG*07#%p637aUDE1}BHo@m=uTf*kJ`BdRSqv!9 zaP$?ucxi-Mxh=zMO;i!8-$T}%3_Nr}fjMgrlYavYZ8#K`X(X!G5r%}yL6GP&8ffg4 z4h>q(@wX8wDS(?Hf%F{gDmQzAND-}KUb=P=6)zc3S6JbPYU`&QS*DHAnuDjXp&(`=*?GF=K5lTk0Hq@u+#<5l2p)cV#T`bZd* z3-FJTo{FN^E0ULF(M8!p0vBH#g4G4BTOBLgX_%+RX9(5QeU9HC+JK}`v-Vc3@NF$IzW)IWCs7lWojHkeQqW| zFkVJC%M#ecq#KyUm8hB`-h>aIiHt$6wXLKue;e{Z8Pvu^nqH+^qPw^$-*V3Y`YI?y zSF(@|=W-`$pXQj>;vnKs7HkeJbjr=Wel|S0;F>lE7=DrH{rmT=8!r^G;-oX~olh4X zv_(Rj_=O@{jmENGBX6CwkfGveeXP^FxPnWa4#EY_o6m6)I_5h$lzA?%QfMsCV*-@n zR|<6*sWCS?!Ei_BLO3=aa5$$&{BcjMHQtGLedSC;6u`9E&S{y6Tm! zt{lo#ZHd*KNR@ZGG_gK}6)l?!HDKl0mxGocc71eXcSHxQo)9(>5F~ZqveySrJiF-84v7f1ReB)2!W|}8eKTG?hMU4h} z#VYBx)c-s+lqR7nntKe?E!4u%&YJBS{W-f@p33(*waCv%8}Cce1@uVhM)@+<%U z4=75O=;ogrYl)KE(61I>)skWRROBWqj>_81Wk(%1!>FFe%RP1|R=-Ay712%P6)$ss z^n;f1UFG_Wce*Df4tOo;b6fW-`9Ow2g_OIy7$-c^66q~*q##kV z?gaKc+BLM7g#^hD8p*F1#mGcBQ>>eI>bU`Sap$1n1Aq%9Cdp4kamCl(@rEg-U3j}D zk&wIGyTJY%YxO7rif(6M2o>JKekh72`|Cuw71U#@_D*z;_YvA4pktflWzc6s29P!>)}pyirMRxJ|N;xMfyK zY-?7AitoEpv2}u}u8SjCjD{7muSM)DW^H`D8T!pRNkez6A(@tUO5W!4z*ggr0B(O;+;9*@av02M{u;nlwkcfou(BI4=4J#rzQu8jVlDgR*t>NS zAfxoPjN^4pAVit{E(R1yG4#fM-s}Gg(tonOk(4X`u5Wrr1;WZS14AP;76|D;GmV@;W`17uXYv=qp^gUW0AbosRCCM3`nc&;VHQQV3MEa4uK<{K1+rP?8- zzIIVqs$C-7H;BqhZE85-+g0ub{DH~o)GOvlZlZ%l(>6DVk1zP%xj&=BNX*RNaO;%5 zc+|2d?ZZVeSFIuMS!-JA5g9utqgwh7Mo3rc30>4d{^@-eVqiJg=ZFftC0>~qf!W)x z740zUh=wO%O5Eq$9!o{;t!f(vt#n&vAI>8z>F*2+jLnTXhD3w~(RIWKu^QjKYvcXE zhe{O-z&74R7E_eY`MI|ub`u2uTsLldlx4M`smw@@v1I_LXV0%go7GJMC6Ja@1n8CX z3O3*$`Q;XE3(I4)DH>PrS2#&fb!4(UAk{%CthTD@t zFaONW0u>E=khDH52>eJ`>^cfCsT4s;oY5b&RMmHFuS6|=PF2f*%;HKI2bfk99-`{N z!QH?q8W6!LHc%HN*v4{en>J<2sO_2xO;dHS#N!WN?-Ezgihfjc9o_EUcZsDfVMFYa z#DuAgIN4JaA{+qkEh%c}y^$wIs&81M7{-D5G^}~S4T5fhHMT`4pXPmJ(jK4%IoIa_ z`r^Njg%yHKQ#1=wSRBqd+shEi%|`m})kNN3jRHP?gs<>Lv(^c@jE=x5_v&8k|8j(h z$dH1H`C%TLPu5|H*eO{=GyySaX>td2Ez8?;WH`4Lbst6?&;HWH8&jB>QKe@OS~J}8@R&^R8ww z=5Pw8;xZ40>_YTDW{LA&`VF_mJSDCIjzI$QYz{7qDT25b`k!C}Hv$hjx2Fj%u!cg{ zGsJ|~1dl;LKETVK>{RRI6l~N6{KETn-Cl8WsL~JWA7MHLYf}Kvq5g2nPAyyK8c@(_ z+?sLG87>knds}wHd4jpdTzzEZ>$kxK&X<~_bA0EwHm913M+uUZH*XqvjBL>G zQljcQj_|?K#aSFFD_@~jp;>cX^gSM}l_yF9Nn9u1YzCXW8!2R{+0s(hIQwJp$I&0t z`NvBP%dtAK>#%Kc{kSOKTiFMj#DmoW0Ex0@Ddr)Mb~_@ zajawXy6}1(xkp!$Yf%0Kwbrr*`#NH0*RIeS5N4#h6yZ8jv7h}4$r_YDL8`U9A*r)# zS4a&Ab6V^&o$F{lyOLHH`u_y6uIUY_y`p+B=%Gqf{6XZhGy%rI!lmai>esocz1IE= zuk178&kVbB1PRa6vNaEqpnr9Q$S~E$3bJuU9bJhCq!?~##XTI|m~Tza`@Ly{9qlde zm)PzTzapjt)mO^ZoivzhSsLL(akD~5X)Is~OpK5Fh1S5%hW|^;ODB>|?CsCna!2G=#LZu*lJ<#f}ebzK5!mE&MA}kt2jg7VFwIl}DtQck#snB$^ z(fg2hHKlC^M3Y}SvxIQwF+?DD^G(%3W3#qi4Kn6RKE^!%3^YAHhD;TgIv!M1pFLv8 z0xlYBoW6K%u3|Vt?gl_ju2x~#Ss?)(LgVQ&*;kFjU2rKQdvLo3nTo9t+D+LwcjE+y z#F@*13xBTDIUXG@1vXYNI*@hP8xT3GV3nW?IHfUGiWQPQ=Fz`fHBbDtzT z!E>_qkh}vK3!Z$D>?sax1&@I1Jo7ktiVek5nOloZ&S8H=u2suIC3^??*zlxbA`tLP z0=+&1pWumdp4h;CYN3+d9UNmc10f6Ck7BZ&jQA}S&7fy?(%>LmH4!=+Era_fv6`K= z{WYu%?w`c!nmn7R&0-eR*<|gSaF4lq} z6O@*@ zBVN%y%puh>%mZ%7G!r~1RqAnq*(e2vKCBKpE7h5|Iwg5t5m_Kbn-+r4#=}N4G7*oJ zn?thwM?`?gElS6nCGyx|my=9Rk|*U_CH$yUhNJQ3dPLZz>#Gi2><%jObITWQ{?w^; zxWfTH#4QU=zQhtlyc`uQLFkPN&9y5HI>5ql7Z+pBr9Q>e7dQ~3X4+VRZsXWMZ0YJl zQ?;O`W)zZ9afS{!vwM`>s{uj=x+s-Am{Gw6jO5{r3N9w#DR}N|Ed7PTakoO`Yk?V)G4FD_;wBJDrR=(i`YPt$4V0P@5 z*6;(TfA`wBql6Q_F~3L;c~*7YF0p4i$Z_&4O>@K=)dfv&-n86Wzl$L=d#N4s3$N=C zme?BV5*)i^dVXGTCbqV;uE#UjhVg_es3Uu%~W?Z zY5Q57*;-uCpHc!j_el;Pyt@wBe1i=!RU8%iHXBFv)J zI@RsXun()ez@u#x08BQjq%~#`kCXE*I(dMPJa*TVhvoTDJ9ZXg2Q@b8_p<&^JXrP4 zQUx>mUvATr*u+3lsX_VH9X&Fa@*%(C%t~k=(UIQq@Qmm#R*zwR!9KTu649HohZS^m zyFVY{5Go`HxLp|av7in=-yU9&D}Q_zEI63=T2*IK#d$82j@8TK}4Wy{6n5e zD2lDVyLJM%79Gc`=^kjPFe#RT#QJ|E#u;2JEYwne+62FYfBm*Dx9Z*V#|i?sQ(bo8WamA(9r@e!5hn@nKP?zeMFYs zDlU1EI>F?9pzl|4coXbFLI}0AGnh4?@$4^eotTCVj%(#(^EiqwK=e*18aaJ-fJ5VX z%%<=aA{uhbNS{Zu@#$l1mxCbSarqE@{~bgU0fQs8^ETy-Pse9I*Wj*kK09_C5ypl* zuMu*-mhqs4Yfj}DAfZj4zVp;lv5TGpDG-K54ga`HBkSO3ckDLD!H|`X*_Kit(BmGo z3Pr)Z0jdWQa&(!z1t=!F&=3;d`LfX4#6iu}f@w$W7GRbt-aiMl*-P8kpBx@Dnx z*cMNs;R!O>ywo4@OU~TvO9pPixD5Cdo1^Ghf_e{9V|7Ca47gdcT|B3*uY5hUDWkUbcn5) zi({OM%QNgJqvI(~#c}782!5f)Sm%YJIFAN(Ub7vS)#Zk!9TA4zj1}opvSPYFF;{_v z#j({JcIcOkb=ZvO`bFCS3mk}K!*cYRaI;!n80Vp#I7arx6&vq#zzrZecB{c*)+Rrl z;HuaG1}Qk)TYT{Z=G@1#bj5n0l8=3ZcpRB$x%0tPIkqt$kNMsPInrI!i!S(l#Q8;x zbye=7m4WcVBL=C0z0UbDr-1%^jO$`Ty~GZ%RJmAgsHJO4meswKRHcmm~?R( z6^=^gMpbTF)RV^xM^IYs@Kd7=XVq@&u$m5s>-hqQ^A&9I>IWgKu=z@rigHojUSsL| z3cG|wRN7ZnASrBB6&_3twr$OE@}c#3`Qu8HI0t>f-mdA4v%hnnbT-0yKKJd}q!)f* z>uE9T^AD%GhBf)8xqokduBs(cpFGnb{S59#-V z)7GG#eN0DBaXRm~jYZk`p{vjbIGLX_n<-6ygLmvBl6%ZUJ5C%YKXjN8)9aFcL~))m zZe-zwI$7(>an-Za-c4b>=mWQwCC7}#x%U~h=_=;lDs!Ba8*{XWi95SFW_CCziiS`C zI71Lh0Xv{rZ#nR2upbGXHHx9$Is;i_?)C5thiwfVbFmZ#??B{DT5J^IQ6hr9R0Qkz z#c;?`yk}K}j|}i+95H4RjWH$$aqjues3wsx)!c)QNacONb(M?47;8ZuMam(ERj@h` zpr+0t>eg99)IcZAZ1X z?iG`2YG&o{6sj95FXJRUATxAtRVc%}Bl0IaM-nlL#&uxJIXn4zDQ7-#ONBMJ7;^NW zm~ta@CgaX>IhPwSTURc2eMsI=x~ZOu?zD6R$ArdD3F8$4qnr;4p?5|FHMo+jb>@;a zWYW@%GGYk1$_fj7aw+0J?@(j-1~9&U1*5O}3A3<5WA3>nC~qf^lAmPcWRsmXk(_Mt z_oD7xS z6!UT)i=WCuefk63(fmwIj|}B77DwieMx2222^lpDGvIt0QqGlNt_Ll4d7btecTr#h zNmkKoICBpffZ2c9R2Mq|B77aRxPykBPs^4S5h9{vgr=NzdqHIorqtm5X}11(3fw}Q-lJ7x$ujgt zWP?Rezxww-k^4}+*eb} zvsG9gd1Lm$zgg3FdY4>};M(?8`mOpMpxW++_}?6Lp)lkGp2r9|!AzoLIS!MnDP*mG z2e1DM!iBH#G{i--oLG(D(}9vU|I9OrEGJD~xD$pH%1sVBlGD$Kyh{ji`@n& z`&dxc>Ej^(U@4+v8%CbNltEc2^l+s|$3FouIZ9^7_IH%0ZYw=;zyl{D3m6=IwP*zT zW+5jM`__&?NYFuofvB;R!+19Dc-No$Rcsul;SOpVOU6AHcn!D_>j z`J36teKHP*-3HSkpVw{Cu)f=mG37)Z47&O8LPT3RYHm({OiJekX=ybAvOo8yb)3e4 zbulRYRgtJ`&F?R;xujyNovo4gyB>GM=-3Q72pFkfH&r$MOwAO^D_pJmU&<>sB{y4@bhxj~?KI#hg>zTq z@m4e0u23FGRyPjVMo{r)n5*#^-VqqrYDs{o5T(238hb&xo#%voL4s(Lk6Ylh2j5kN zum z|NjHA#B8sK<;yd?>TGYqZEPpRqe;;g=KAnsz(kjDaE3dKDYQ`>t6)CP;*vX@GgNLH z{S-?;pE<5sv&qw^GLOh~a6{HnRMGy_@Ww6UH0E^9jYm-MMBi|DQ%nFp3X5qhZY~Ft z|8vdq0d6+=h+D0>!WP0TBAl)Qh>u0B5I6vwm0|lwxaJ1sTmIp#xufzeH!}o?(-|m@ z#yC|k>jze-Ib9_()5#sdA?R&9Sg}%mSjyC<@!$VVjX}yHm6qX^RuEEcCISy7PEYYv zVoW;8ZveW^R-n#gdQ~0F#-PrydsQ85-A0`;>qwV@6^0^lv!)ek=%hB<{w?I3qAhQd z(Mx7M#dgYwYhZ%xWhrz{lU?fE(fK4+I&uINc^GL072eaPkCLUv>WiKEr69@WUH-Xe zB7L2h#UatG?f|-|cWpvmR#yU{Qs`+|#hOLk>17F!#<~s!g8#tNvZ4|e|9mzd+ zs-S=ReMgQOsGftzniyKoII9a-Q~@g^09h~m4ydI!Zzhk?VhQ3Z&2h39{`s+u6Lon+ zbS+b%l~s&5rYs=(gXFX~V1uWeB1KbV^wXoH7w*xj83YtWNJX5Uv504?_^ix%hQ(J* z@QUDSu`Jqxch=im?2F`!qyl4e$Xz|VS3(;-M;O$>tK*!xAcab4*r~XYE!fJtV{}3j9hZ=xDD4=?4zW(! zP_&EU<6a-TP`vNPsSj9PsmR{sZmcg_yGPly5zbx=By4XkC+YYjicZ%sy`O&ok^#ys zwV6L6qk#)c`+dF-{^I<6gtz{}H_?YC4STl*-zbO253q$9o1?nDOx|n(at4#7qa~C!pq;gC9=pD4FvH$r zZ*8QTe={R&;V@WDkpfYA;Z;i_D?~jbvZ6MQ`Qp}7G{u1_dim{l%JRYlb&1RF&v;f0 zGy#Z=WB{fiLTk}o;wUioP26tfn7{Wf%9#9LIn3?#+=tyiV(ZOLy|LLv#z0N-&mUHm7mse5G&IK?#8US zXBz~%YL)gr@)w4LtKdxV&(EQvEP$zmM1s&k2YT*2NiYJMkp|EmI7Su7)@K1h2aa+P zRZY1_)E#NQos?R``R)5C3H$_v!*;y%h zP@*$5F^6}_Fza<%U|s#%g8GIt(rQOkDL?qDG#R)rMUvAZ_g%3g-caqtxe)5;3Z-Jy zsO(s&fH1oeD513|J8zh%I?Jfb4BTM*bCZKNZ~itPJU;owgS^fKK_eaVS}^(i_Xp^# z0rP^7^-8FxM#I_2OqSmo(b#+QM$X*+Lr){0;QMd;cjlLPENG3>ptQ4NBz$E^A)t8x zae%Pz0+6aWg}fwC{>{vJl)4&pdKIsQ6oH0y?vemJvMD1vJnDgcnSYBBQD%T?#uayn zj3f$R1V`dCk_Gf*t+_){BS#GU-wBYHh%4VnTAaKwnB9Y;k9LXS-6l3GPIUo40 z56Y%PEraXcr#Z2LB8`I1EJ9uOJ!@2a#ixU$Xcd6ucNq>2z;`np1q8qEsKA@&%p+}S z+;YYeWWKILMIGR9qzfzGs4ma-uZ?jrRH%s_G8PvH4vXkloEv1ux1VDQ7i)duTbOIrpCA|U=3^#i(%A;~NPFl;qV znk5l==1FI`=>cw}VvCI#{WVq~`5x@QWX7S;W{ogd=W|r>=7j4YI`nf9m7=oOk#r-C z{xf9PsdTKR(KskzthM|C2_4_?I>f;TIP&OobGn=fPri7?bk9=5*D2@<^A!#J!N5)8 z?U$P1321|r@_{hqFq&c0aOO1EkfXE0@FwpClxm#%kqbPtwq7twUKuyHoG(<~^GQW^ zN2~)WN}WqIjY2Ph z_ORbdJTGd>66^tzT^^U#*b`wkiy1*4oG3h1C|v z6pqmyDOb(J^+>ec&0AMg9Qk|ws&3rjOozxZi=3kmq5BU=e_|52N z?@92Mq8Bdy)}%6|H>gyz7Xh-Z$gOAv|6_V8m1EGW@vJ}7j;P2tXoa}5?s8JY! zah^ z?&;B$?g@7b^9seIX7(2c5_rrL=Y-i}BTfp#VJqqqmXZhD1oxo!AT+GB$qA8BJ8OuO zofPODLg0t&hOP%R$+6F&>k-fm^NK(X9G=qVx>mpy%Q6Wo2FTtYF?;uozQqPCB&YhS z3I_?N{3$uIT|gT+yrKrK@DWZ?612l?FO~^_K#{adxr)mYRVZpd^C>N z7$!N zV$R0;hB%(H*Zhio;vxf N(P(=6(e2xx{s+`DqL%;w literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-06db.12facc20.js b/priv/static/adminfe/static/js/chunk-06db.12facc20.js new file mode 100644 index 0000000000000000000000000000000000000000..c8b2a5ce99bf70e27ef9b300e062a0a712533e77 GIT binary patch literal 5112 zcmb_ge{b7H68--^g|ZhEB(h>8CvXA^gs)d8Xj5O4J10dCKEYU%D~UC^%OjVPRaxJ? zZQAZzusucm%b)YZbfx?=I7 zR=2~^X>!A+d~@+OI}c~IicPAOXSn3b->|xpgUXa?Y}jNe%7KoQ$BMh3Uod~70_ABx z5L+%T|CxP$uL=@RawZseNBEmknz~ejV(a(1^+=DI&qdT|=OrDu{^i3b2rDZreV&p~ zfBS9?VP=J?&tno^EYC9tYb%U>UPL?Rkpm{GJl_+62y#*0dfn53@ua_@1&ZrQYZ$Fs zm7;K~JmYU>y7VR!zgndxUU()bO1X?opyVAM#scvgh3)=E8lCVAissV%U}WyGWi9W9 z*>4D-U40U!GfzQ7C6(bzohF0PlPL0ZR5!ak#hDhhSp-N%`BC3W#eCo2wAxQ6H>DJ} zTeB$jYM|t5@TM$bBm0oaQs?6Bn}MM{1EtMirfZdSC!apB^EH=2l2(Nv$Jm9Qr|R!( zr-kv2)e~x@%Ub?Aq<>68W3Q<)y72t%mK%TT`&}fvFjJ6Sa70mLYtJmwii>hy=kUM6 zPVDCKczpSJKshkZKhA&I10x9z_HMZ{|NcXamawmf;=7l>6$emk@wpGh7N7f2Tz#uw zHBfX|Ei5c+pC>z5&8;x;`J9CLbofleBw89Ommh)j6 zYsJEtDlrj8^v-v|-ei=_x4O*34S}dp$9N&CYNg90WNhocd|Veet9!(FrbUvfdH7`9 zeRP;0S+&rs^Hksj`c}#$EoE%N2FSeVKxlDGE1cxg2qS-#>(EuigJuROhG$Ba>cN!vH4A zKoQjuifEq84%M{etMEgy!w=S(gCOmah3v@U$kIsm6q2|60p302kB9WpSLIDv7sg|a zpy!JH!)!XEC!>Z5UVWYkIPE=32OU5MCU}$$crMLCCjdJ^?Zav>Up-EvC~8b>F-@^B6)D|M+ z(htl+s=mz-xw`|#+yo8!%cga2z|f1(I9%V~v*%RR)pJY%@{Vm0>L9i(?s#`!BUZG2 zx>A0`;m0eX1u{8@0D0 z%_O>NYsh%iAneeohnlN8j&X?h8Qqt(#42yCvNX641hTecze6lEVHm&of)eFdS7UxU zo&Nb!-Npa$>OsKUR%FK+>O?_RWGQ0%H}pCgp>8mJp7>lv@@h2Y8vn-AmU8>+^EuTdm8ZV6>FoxzyOvTNo zAHPqYA;)|bwK$v+4wt+0Y%^aHdf*3&HpXCP!JO=>cEVCUk+Lx1c#@&Ykf zdh9=H(EhMz6cxs`CKZ{ZqA>CT+jMEv8 znHJ9NN0~{VNmWss9ZND1%Z1Jo3@f|dIop6Q zJJmS>H+J$eU^`^uNP1{up)}&2lGSoIo3564EVAqdcfh{-FmmJkN*V-tC;k1g65T-F zfh4O6Ip2Ym(|X+JBXH1pYKBy8L)9+3AWin zbJ>|UFu)#9dbfz6Ym@E-k0e@w3zqV|3OBcMT^D=VY&!1~8IT2m?fLI#9>YTB)6{!? z>&XD$z5`e|u4e|I<>ME)-9gCN8!Pb7RGkqc?94m3{n)Aa5sY;ujw9W>%RhB3DW zb+unpN2?Yi;ILRFj035gI7@+aT%DW2u%)R#s$zE{jf{KwJ7aQ9REWPrUErSG*80(U zzp0HO&fKRJTVccQS<6c8C}1nrUZ&boFVMn7xkjDz`EGo2gIj-LmUfOoI?v@y)R{r= zJIvkz!ye&RnD_&|Lg@IF*mWoJ2+7{1?W}1$olAelT{qZ$Wxt)?3mPgce7`sVKc~WN ze-I4h=~{Z01Ss=RIpw&yQo(SRj80x9uSX}$e)lJRRD_BrKxby#_O}bpxZZX+wIh!{N?%czYZ#0m$Cc@?nAhBfBM%&)W4?-#wRlo O$0wuU*9z~iir)d-`tPj( literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-06db.12facc20.js.map b/priv/static/adminfe/static/js/chunk-06db.12facc20.js.map new file mode 100644 index 0000000000000000000000000000000000000000..b07a40083fe91a8a81dc36e365dd72ba0c9ad26e GIT binary patch literal 19586 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-16d0.6ce78978.js b/priv/static/adminfe/static/js/chunk-16d0.6ce78978.js new file mode 100644 index 0000000000000000000000000000000000000000..497bbcb88c93654758cb644512e03b33ce5f890a GIT binary patch literal 1576 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-1a7d.8173d81f.js.map b/priv/static/adminfe/static/js/chunk-1a7d.8173d81f.js.map new file mode 100644 index 0000000000000000000000000000000000000000..d5a2b4a2007fdd81c6add44ce450be1435a75edd GIT binary patch literal 57112 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 Kt5`2Lu>b%AbtEqU delta 64 zcmZ1=@PU7VEwe?c;Y0^7;Z)m94W%mg@+c)uonqTey*!Q7iF1t@i#J|4#wG}sbaFE> ORMNBtOHE$R?g;>zjTABf diff --git a/priv/static/adminfe/static/js/chunk-1f27.d3c35fbc.js.map b/priv/static/adminfe/static/js/chunk-1f27.d3c35fbc.js.map new file mode 100644 index 0000000000000000000000000000000000000000..1ddd765a5c8654ec38f7ab00bf78f24d04a2ace1 GIT binary patch literal 9090 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⊄to`In~ZUyRfD(a#Hqr`P+Gy?NEVeiMB3 t{4&h`wcmaNB0VDm RV*}&VG;_VIV!hnN0syEa6r%tD delta 15 Wcmcbnx=eL~4U0jlp~XgrG$8;iSOoq6 diff --git a/priv/static/adminfe/static/js/chunk-3d1c.20303ef7.js.map b/priv/static/adminfe/static/js/chunk-3d1c.20303ef7.js.map new file mode 100644 index 0000000000000000000000000000000000000000..b3d1eb3ae5d3bea2f9886b4071a2eade2a57946a GIT binary patch literal 18519 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-5913.1d21a547.js b/priv/static/adminfe/static/js/chunk-5913.1d21a547.js new file mode 100644 index 0000000000000000000000000000000000000000..8730899632a1cce824d0413cd382162d9359cdaa GIT binary patch literal 27091 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-5913.1d21a547.js.map b/priv/static/adminfe/static/js/chunk-5913.1d21a547.js.map new file mode 100644 index 0000000000000000000000000000000000000000..3841396c45564bf1a7e72fad1aa2cb8cbbef1d01 GIT binary patch literal 88770 zcmeHw3u6;UvhH6|IBaYd$!`pJ!xCA3;DCW(SWY%@eaF&R9;}DaNHz}3{q6Vrs`@pf z(aRV@vdOZtG}B#Oudc4HuI~PL<2>%ANw;%jW3_xE?GAeNIK8p)>y3-}=q#$AZY(Y? zE-a?K`r>&KU!;qJ6vY>lP9y%Xa6X71E=R}ljq>=?^=|vD+lf2Tw%Vz~PPY*sw!4i%D^3sFNhdk1r|Dt*q2G(@{ll}?pqX?I8%f$fY;~hX z+&g@iX6vxHc_nzVKrcQ%TwXq0&X$D1vn5-}k@=b)rv1xS{Jfj?pA{gv`XoJx4^XXE1o|w6JFAdyS|c;m>*08gK|;{Xsu&;A@g@#p!9kdxr1*lO)BT zn`yt>W3jX!_4zkC@bvJ!%}*A-Sw{=~c)Jz1!81N38i#4zqQ^!7CiPki;|YF6{l4(L-io7Mbkrh4 z&RS7DKIyhFGUC@wLTDQw5MMDb01hY6BbLP|8M zQc7=Z1y2oH`c*NJ?;rSS`!l{aGM$^XSAA{$s_cH?Qz$;5g~E_njUFjNgG0=gV6r=bw9?4Zmr{{W$+r zc~H;;9X*Au`#wk-*)u8mn}!N}HQzP|{XY7s>SjIa)Z

Q3f4Oa=|YXq5zN-Mizhi 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 UZ=~G;5^G=J1lb!KH*S3T|BmKn5C8xG literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-1fbf.616fb309.js b/priv/static/adminfe/static/js/chunk-598f.dd8089ce.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-1fbf.616fb309.js rename to priv/static/adminfe/static/js/chunk-598f.dd8089ce.js index 5ad34d8010a1d3d58cd9aec26afde826cacccb75..618a2ee9f9fcdb66358fe2ebc2df8202de3813eb 100644 GIT binary patch delta 65 zcmdnm#rU*~ae@uAsinn6`)@7=T>ART3dQ-QMaikYi3J6jdFi1+KDNmjrFq%9Ks9N4 TDJd2P7M97WdRfJKxrqe;?dld7 delta 16 XcmaFb#kjSLae@uAVOr8g`)@7)IbsH* diff --git a/priv/static/adminfe/static/js/chunk-598f.dd8089ce.js.map b/priv/static/adminfe/static/js/chunk-598f.dd8089ce.js.map new file mode 100644 index 0000000000000000000000000000000000000000..4ebe699339d8c43194c9a4be6c5a80bbaf8c7200 GIT binary patch literal 66937 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-5e57.7313703a.js b/priv/static/adminfe/static/js/chunk-5e57.7313703a.js deleted file mode 100644 index e1636617912be106e167b2112c5bc956a29ef96b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 217441 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 H`{Vxs%4Gr5 diff --git a/priv/static/adminfe/static/js/chunk-6292.0e668979.js b/priv/static/adminfe/static/js/chunk-6292.0e668979.js new file mode 100644 index 0000000000000000000000000000000000000000..1e5c339f274599a30249058d4754483d162ce751 GIT binary patch literal 231394 zcmeFajdt5cvM%~67~VO{)C>j5PMn>gk4~;4%ZVqFt&!x(%=Yo(f=Eb0L;@TF)K3)O zwO`}BzF>ECT4i>gwwHukK9{j-ng)#y^{S!>hl>Q8?Wx zdG^aM?>}s~(|LT^egD2Qyqt$un_oTq%d^gh-hJoK|MHGH{quP^OoAxv`n{y*ZQOU} zvG2smEEp!87uVj*iFdqi=d10vyPb^}o*Q=K4cGhF>pc6{S8waKJ{iV$+16jad3RcD zjc&g@`^#e|WY3Ma{O8lOLXE+P=9vxUSju`0}gcOk0{rq3y@s(LWC^ z%O2l;^}Ouy-Ni}aarweelf%o*1ddOW?`pRF&x`n3wk=juX#258NLTXs^zG}bvd72A ze<^#6iIzQ{kG?H=+EwMVg z-3ReubQX-QgS>G+^ON~3>`eGYXJ=<8xeQ|Wk8u*sd^b+K#CN^v)E)WP!O;KM8+&K| z_{U(BSO}y$ak!}-VZUgz0U`uF2UtjkX>qfy+ypHD~V`NU6>AiOAm-JZfI zh^JmMyzF+~*=^!Z?>_O)`biHRdHqPB;Pw2Cj~gF*QFt;xn*@pJdE=g_zP~fZhoS4a z6K{6a)whJ>chfb{%bS@uO<#8Xjr;Rx)_w6}Bfbe}CcZnJ`PVzX8~V4&#{JO4-Ll;m zKsxH>c28dKe92}zJ75w^Svv1`aIY7bM&2TWBeflW_ts_ zy|dYTnshsAJ5_&Q_hs;jAIIK>-@Q-nrog0lJ{;mn2m8U#`x7i0jbqu5*wr5Zm@KA_RY3k3}gVFO=Ar}15vTX?gJ`NR*C z7`<>$*E?Nc{=fE5PJ#LO>xb`0f9`B-^v-t_f?vDdMt9V+`jvgptXb}73b9XTO<(EXy3tf+b>rU@I{_w|}*xv~dYUZE!vuDRkk{Qr-5{>*Z_QpC_ zy$&CR%^Nxk9lSFq0}!$L-3$_+I#*rsXZ_B*@H`riqZ{XJ91XAh5srs$Bv@uzTzliW zpB>zttL6jMoKU`hKV)n&NDt&pu`+Ywx=Alx=ak4vC*NTQJAwlX;9Yk+j%>yhb0Ufm z4EM%f9QQl^?R4D1yydGOFLAp4nXD*wW_~;$Cr%JLQ$L!Hedj{3%h5w&(HkE&KJ=dE zhEe-b4!5`SE$n7vr_$El@MG$s+3W3YeQE+*XjxtcA z^y0*y_HhsNCPCQW?#02+AU|Vt=mT$7MA@oAWfvOa)k$y>IuT!@*a%R0K)czIjM2kD zdKjo4R$gLBpDl2#WNi*^vPncuehOhD5)-(D8=DXdWhDo4mxi^kRJ% z;DPVZRET)~YwpJ+$<{gh>ee}%CkYy)SB_lz(^-I%e5cRdI2c~xQqi0e;kuA3OUh^fCL`u7duUIE&)wJo(Hbe`b+?11$0xv&gJb+R$PjbH$er$rYEMz8rg8 z_R)%0f_2&~dq0Zm6=O+|KvMZ2u1G7bRk5*TMBKfXh9 zI888HFAi%dyI%@ZnozmuLlATzOHRiS63|xT7xV81y<}G*tKxJ1pMh>8>?nU;S4L!r z@a3BJ(t;DR_MQ$gEiqk)>wJ6Xj1;B@$&>hhhmQJ>NS#ps5HFJvJcp3Sjo=wy!f0@r zOvc2tXp!~iG8kSu!)OM^b{awYagwNc*W=)9Ybr;63ucKe4a#^c8W4c>Kj{=)-@kR4 zd1@@#^8OCNN z08Dn}6j~tEDWs!u5GPJ_?)V{1cI4!c%q;PRbCxA94#+Q_H75mcci)|UKiGTw=H%Vs z{_)`C^mzAl|GU@wCl=K)z53yGFpEOcK{{Zo1DdAm{4<(6Lr8vjiX+aHIwm2H1U@4g z5`FZNzS6oar+-hp{&^HRXZ2ttnFSD5i55u(!<90Vupw-!Etj6e(VAo_sdNj zn8d?HJtNu<&1^y8SZHD{fp_3C8loEjzI)q0t&6cNp z2TUiP84uO^fNP>kq=y8H(7(|$)Ss9RWsP$DY0bobWCnoBf*$ZhSzkfJs@qTB!*Yo) z)ai2jU9(%!tSM`>FJ!>FE31^~gto4t8ZFdwO5311XhFPWrm?`xLKI*qpWJ5J@b9Cz zpvf(Ag1qKSeA=8FQ0t|}Ef&igD|qfu7la-yR(S-qk+roI{4TGOG)%2mNsZgClG^rQ z{JU_SFTVbZ0~++z7hknl>&eN1wbX@J9LMAK7>vd(mU=py!-5bI33V{j9{!kvNw{+Y zNG0G%m>du&TCV=|;H2*AlW`mKjlyR%USahhp;#g2x?uf4f)=~~Eg4ytN_LFtB+$3U zbZXoJ0DPXQt-|!W0@{<&aL2#(fFphne?re|u_+BMig&MH)`ZSH7_|lt+O~xa@kjwK zYIOnUcmX~gbWbYq-QW(^x35#5+Z%=qJq0&mQG{_%`I6cjGYofVLPVH*w6WH{tc`uN zbn-bKGJW%KjHI?wDWzLZP9R}aV^kAn)9hMFhYpKPF&oy1x!;n%=2Pc7@Eo{|5WL4q zWSP#Q>i~9NOYH&w65JxEVxZ_buaxzo=X}S;i=K0+Ef&C|Waw_V&TBeaBx|rG#Q|qX zn>ixx@13@Yyny5b;thUH2~TDbf-aun94^_+cbO#9xWBb^0nTrJ=Hl3Hr8{Q*brW0# zTL<7=H>2~-6C<7WX7HKlgpo4ng>Wc3_o0rNfo+YZKC$^dP*S)B^gA%fd*Kytg;=4? zwHQ^qn!8`2yxqhSWxbXGMPYnx6>7Jr-9aiBjvi9po!)w|GwJLJ#j^L*`Veg9|7#8*4``+_3mOU# zi!KgtN-Q*)04X8$8Dvo{uF->ybfS*)txsM>-b{}A1uiq6bl)-20;PF&(E9}JxHFBW zb2wu>{E8>!c@o3N04D>s?wWhtd2)h#=>+~$I|tsaed+P3#5oI^A1gR5fkZ)58eIkc zfG;F_cj-=c2q7-LYnm;N|2h20XzEJnvtV6D{8=>+Mu`JO!Br!aww4Pj3Qu))8MjBg zR}e$=Jz~&apkGPt;pqt!nnE?9jy)58Kiq;FC|m~DMbu|dVZu9T#*PrvsYSJ{?J$#u zYUn(;plul9dObsUfb;J7faq;qWYV|U|HSUj1|*LDuPs(fZmD%{>7G};Pzdblt!Xb-{qcM0m0ky{(I4Se6ibCnrl94NZCQ%cU_Ny_2KU7F!@dX6^& zmpGk1L8}?OW8o_Xo{`xf&7W_^Q-25@{7^GDmLP>YOtUt3=wcKN+1XrVB$l$wESC`H z#Uju^-5~43ja1IkUE4EFPl4h4%1F{eoqH-4HdVEM3&9eG5Loq=>Z#I2xFn4Zs8MsJ zOxg*oh-o*XpV1B=Sq7=4^M}5TQa@+y*Q#GM)=?;BhtfRg`>QFu_n=pW4Y7{qOV89D zavR)U&B2}Gg$o{(?96wrp1I3M6x)z?Z?+-31q(4xEhzSJq-&`4^NW&p54tclHI9HN zYQYvR?${TD9hlSC%MVDpHV`+q^9|;+;9-_#k6^Z~xVo07CnbP64WD|x;@LSBU0CCz zqkU2TjL?BTwVSYtqs?N zFD%e$dAuT~eaAd?V??V@qh*$BrqD8LgJ7Ecx5F-3OkLc{E@+L2RlcY^Ry8;_&1kb) zmrXaD)if(J3rzji;w_Y54=R zHdJF>8p3UI9DqDt5y?b2eCBRDN6KE-6x&XtD=2mmg2bwJD3FlxBhM3<7)Z4S?Mf|c za1-idp!ygDp^k1`PjI7#Unf6|kcBLvE0`a$p}1sg83%|$M6f3rr?Bbl0u7HzG62HG z3xVHIo?<;LIX3e;dL74b1A*%pVtmhGxqw?3_heYCD!&y4$bdQ+po4+xV89&+eQgxP zoC2+)%NDTv!G}%FiC~|~td3lIF34y}w!gyK9kv@l8y%gI2O}%BR|E1M;#4%kj+z3P zf?PDFjs&=Eyk%18mi5;HwBq~*BP!|dFJ=gS963KlXQajF5!CsFVu(EBWYMv!<5&n` zVS*gT%Eho5(w4vzCj$lu9P*}wpbQ+K2h!Qr7hn0$6=_%lWuV^vgmC?Zdyx*_VpCqL zc@uPDr)C0Cx+#1{bKCLkOE~t;XR$baF4>XC4^Q2AaaN2^HIAm_7MzBtUhJHuA*y#) zh-!2YgjeLNusA#w7^}a8e(n>eTIr1=Zb8YZ(P{}V!w@mSC24BdAWQxZ*`X8F zfUw_6GL!qx%mx`RGtL$>|+n( zyqQlJ44E-(a1{sn<(F-4O19qcqIqiy$AG$=Zt~Nc=oB-|_d%)8dhy16aNhmHHZuFD zWrsVR6kvE7f3uCyju*VCs=qe~Irm2|5jNNjRVN>P&|Lw4@gq*MhLO?FI5GrTI&Ly@Fn~`3EeBch&i+aLBR3IKktB-bX5tcP0H#b68&Yd8y6+*Cc7aeVD6aZA8Hj*!6;!W22q62+A7l$Wd? zZ=|;fF{SXDC!J*7qX1WTN)wn*r%+r{0r~BVyi&KDzt0T}SJB}#x$Vt}jZ-du+6$lf zps9mgsOJHtch&hws&4)QO`+xkXzYeT2RS)AJbrI~%H?q!zam z^cMl81x9G49p_gUpRQH&K{8g3Pm4?mMJ)#9L@g6)?0yA^%dUq9Qgq^kmF3{ucyUvv z*S!toHewQ5rd@3mK(P zSnb1g9kObly_MBIp#N1#r1cre>w47l6%{>VN2`-FT8+0t#tRi^=I*5wK*d3|xKEIP z1@|iRiU{Lj!lPpWDGU&4ybwnjLguE>AQ)QPCB@)tgp!Okvhiz3DO34?ss1V~V1^(O z%U*(QJOz`IH}TWDCHEPzFdEA6yXOV9xRnn%XTQzHROFh{5R@eU>q@k^m*SoD z%V5&1rsM-Mam&irItOX@hxE?U`4+3cfO4dGy)RKz(mu%S5F|9CLJ1@$QIZVW4Fwks z`eN@&w!|{PO82cBHcvg$yLUzUk;22-4@Xm^Q?KENosJD!B5j02U7(p-b^`2uq0#~} zlf3K-D!T;yW;sA}Ps2M65o5go0=HphLkRiq(QA@Gc`V7D5W|3t9iyCrh)=NtEvN!P zWki-05^@zK(dHQf*tb$BtriMGX`TpQl=jsMIVDun*%I|KYKziObPS|Esx)z$w>!Md z=$HUU3XlY!Pl>H~NF5Za;iJ)ck%IVv_+UCgmAvptffrU3#4y5FJ0~e4ysH`E*D5pC zGEP`0Q-!sI5_28<(}*k|Q%Mp@KR@S@{+vhpH;_mAh#6xlQI)fY?mi@AY>rRPPgK8H z@oIaia~*5%fu@e4$L|hxq`%Gc;1U@kk)_t~fSKZ&EPB@NY(5z%#(25rrf@OpZa_$^ zj#_YpGyfpS1ll>tiWi3$$^%n$qu_n=m7aW)1Jd&*Z3gv0Ti46D%19)b8@ z%>0wT9a!lz(_84rOC8a5Mf9DQ|K*M4rS z6h1Ux(pYD&#wAP)F7^P)5JuM?viMy14y;8YC{e=3k%y#{-@Sg5?k)C=_l`l!`Gy?- z98s_wE6Ay6XqVx#6eHU?(%AqaNb`!cK)BA~6O2A5Cgp;N3zVaSl92HCs5&vDd~TjI z25OvpoT&lZ!lhdfRm*u?pzlL}NMlaEvB?dbUnvI;d}q&r1s7qE0G(2xV0{>y@_-=w zh$p_EU&v$#4JLC+x`VQhz}eVdDr^6nK{8SYm=JG*IiiXV{aKq$${aznjpt+Ug3EM( zw0%SHNIo4_j>q-6Gu9W15_zYKi@}14iw9go+Q?WD@ z_PE}ff$`W9amX7F%qMgR;2jEz0EAGP3y6OzN+B&H|12gbN72(aE0XkmEFTDr(`FOo z3L!KdRMP!FLWW}+5q|76yGj}PIU3(OHIH55yJw4d(aU~df)f3jl zW70aI8k8CL|GGwFO@AGsj{ki7?s#y#fArQCs-4#ft{tSo^2RsbU5sp4P=wG#p(~i5 znFWAd(cVA=5EOG#DVbYrBytut+edgdth|lrqs1=nB6lEVSfYeoe5)bRHTVN;9kC|? z3J_A3@^&g(Zqf~h2&ZoeH6Y*(>RcO;U-t~ zLPo+E{LuxH16?q)%dnc!RlpeTVs$wt5URes&QeC`^hf^L{Gy}Bk)IfdG>H6a6UJ8< zM@P^!a?wt@4eR$#`(-+(U#f3wBZ+aN1bA2A7aDbb`NHd#V%Q(CQ!*^JB$7)H3&_jn=Aj6N8lqB*W{|b$2#>Y$vBwJzz6zEg+zFpV;&xrRw9f+V9@H{)Zzyrv+3lpz;h2yY4!CX9)mk|0x?C6jt~Ob}pSS zTkf)1Vkxfh8SC3{$-zJi9)y`Ns$|dH87?|bO-fv#o&hO_0tgeVQ$wpEWv_#7E7j_0 zBuIxr6&Ol8OG;aPbD}?yMr6vU+RTE8x^UCw<8#u$;-aN`1ohQieVME!5`n9SqR$(Z zMa{qzx{z9*@Fd$H)tV6MQILrgZiGj`2O&PyTdYOUx*}^|qlCR7gh#bIko}}H+KOd* z2d!>%vIvahRx9tK?nw5r$lou-z9UtcsTuz1dQL0PU3b)O?o@WB5izEmq^r-FhHdU_ zp{^h<^3qkF2z}@ImtQ>FV61~~IjgN-xNq8A*KGaTT(&X{bVn`VKzE65PGnjUZT#5+ z42Lk9!SdzN6`?zA1`;y6sU8Nphn2xo)@gH4J&`B{T^@*UUUi4*nPvef$yB)R7~QF) z0GUP8Dg8~ivu>2r3_|O|mcI_=`fo};AiOq%H;KC|!$)mv$wsRD2WU7Vv|xm&Q=q zNO=m__;4qo7EogVC>XMJ6I@#!vuY`T)CLd8T#G)G8p!`*4JlC{rXBsB!M)LaUg=iA$&;%Rns96>b!X4!&m9R)I2acZ?@C9>+3!M4OT zm8jn+m5uxIvrK%=tBI9dCyRPa!IshpOK zi{iVTqtr$5VCViE;-mNx9L@Pu`LjdTsm5=oB>2Vs_xB1xG*RRN^-#ZF2gw~8xoN`` z`IdkAu~*hBdWLWxRyxoa6o}kKQUN1xwRj)pNKzWgy84A7}MdM(2S6JMe=l~sHo$WsC*VwQ*mVGr(APFoGEp*;G_j}@@UQqc59L+REbf6 zuNI854P>JBv%Yf-T2AF?nE8SwJ2(r*Kq|Ht8Hka?mNWEGECEUcRwNKN3rL=z>R5j= zJBKxcrUt(mp0f?vQ}3byV6CrZy1P>;J~<_%VKy@&M=7BG2ySUaiQtrE6g=JqNSrDU z5C1sj$}=bba0e5_I=szuf6E(9f{_1!NenJTAc$1KK=f}Fy))5t!3i} zdIy5R5eaGxUKvgcrl!Ehb}?;bgew<3A8A^88`V_GHuBj23A_6y3YpprYaw8vjZ8H6 zSf3byAG`F2QMfrJayWzrFvUvk_h}*CjAw<<)z>8$xR0FQGym8pt^#iL))ievC5gV2 zw35jeUeGCG!bWZegaJ6l*k`I|q>aW%yUdTR6@ttXJgIaAyJ)fxB~TXb2+;STToE}c z&=>42p_F$(XeyAyAey17yCGn^Xhb2sCsS|I0Fla?*?Xjy#7Ir<96&92@=f4(#}0=A z{v7fXODG4E*AMQH^JY>GAJ}|SntO=E_}2(A!#Yrh+!F)Nbc8bX|%J$2T}HURXYXmNE5nWkJ6 zf)q4M-1am{0F0H+To#c5=~`!0eOPux|BhIwGphP_r^m_JY4VH%A$qZqMgX}Q07i2Y z0JRZ>qw94cR2=pO$otpnz#ZK4|C*zUB31)OVX_+WU6Ee*A9@ssEl!pG=uI%ZBBs~y zIv;wdlW@W*Nz6mds<5MON_pg$*%kVod1>t!6btDq`rEV`-S~##;UDJRMKs0TkTz65 z&3g)rPv7zn`(0?i!w>7-%+ODS)o0&Wt!6{Jm4xG`tl zE+B3GEuPCGVXa)EFZ(J0Z?VO=`b!MPIW6|MisLTwa}~$4Ye%Lq%REFcm)PUb2Purk z#U5UzQdio(ZzQo!Z{ppej->W-iTlsDdrAe;fBM}2(m;>z64M9ni2$(-wVS`2QhGtt zey)D!J9zdy9sdjeIaUWI7d{14W^uHK3l_Hrr3o!AGys|KQReqN9m6~^tB_|uO?`N& zsXN1ZRQ#^^*@cCB(sYXSs@cxyNxrZ6`r^;G6LXNHt$u30_U5A?+M3uiv>p||`yw4% zfA)nnHq~X0wm|t2MWWVgJu-@uj;fuVeQFoG@JwX+M=8 znBfbb9G)Ikx2Km2+G2b_!eD-(bNxYeABV7@&Vq6E8qyCI^%0CO=041ulgeJq7uCJI zysL&My{m31js^$bnc;!*;Iuxe?&rIOs4Z`+TOWX%twt(&i=#%~rT*+&+%iDb;!y@w zrmCLK))xDwf^&|O5m^irqWtyb?HiX)cnIQr*X{Ii-B1H)no|*J|8@}H#WIlH5kITw z=pF^8$A15PXaDv@w}l0z?^}I!K76!B`P&?8aK#zc8s)@hlJc{)+hE3|+@rM&aUB(T zdSv9LkjjpGRRziW6gLT0z#1mRhPlxOJ_$o2{^2-pzQN5C$70dnV?*CDbE zuur!A2r@l0a%wi5^55z*5^aF}1d>xSj|Wf##KT!|X17)>vh_6-hPNn$mQHaxk8P-A z(yo}V$nD&2r4=kzM=}fR0U{W!UnHJ_MWw*P+*1@&0e50UmPJ|XD-ygue)!ls-hl(s z`CtFzA23QB?s#t4J>KY@atL$y?e&S6Dh_5-c=Pw}Nm}f8_H{-H&TWM-MTq$Qd+=Te zVdx*a-p3_5udw%$kpgxN)l6|w-&5Aedt?qY>BY18^>tI1#7$S{8UKcpkC(rDzx@GO z*gy6FUDGKNwsR8|IArC%Ly~%vP{!tyaf(I6MQS1_VJK)BJ{~<;wKaV}qVD|TMGG)5 z*SrEy_v{it`lJFlL%&d2;15rCcK%QVFm1BcE;hi`J66#UZp3=0$_Iod2$dA{H@wro z{BlpQR(M0rO2#W`7psPpFR(20UqdG?h4MO(?E zUez!&rY1x>`8ruqB?}LbyKrPom%3U3*MNAyLIjl0O1!0T?tr?P8EoA9LJqRI0Pa6l z9qVMH&j^?O-mm`rb0vgs2R4vNknCN0NKqSiHeL*=c<~p=P95U>?0o$K8Vv7Bp8oq( zLfGiN*7fj?Y2NTupkUj^5mbK< z{2S}URm2aa2X4k=DO_@|(RiurY=M8XGic@xUZ#794K#q@Rzt_tU6gF3LN*pHsfZP= zSQ-`9LnC6F(n|afN zfb6xTLjvTRF_Qm89O)2lViXNe9Ejwy5WbR<@w8wfk7~uJ>06Oz?bZrXYeM)LH;`$y zUEJC!+_b1EdEUYCky$#y>?}j|CBhM$E{(OpBl%V!!{m$*}t!w@Z%&S*u&Qcavi!2JHFef(;1SEi>{0qQ&22WNCo_N#(!;UGk znq#C%d*2Xd2+Mv5xS-pXfZ;gtbTteli6+V-Tipv|N&*ZKV*;!eUJR1z%c^mACx!li z{5?YVzJ-(d7VtEs`IU1x2AhKs|cGcCAIU!W4gxW2? zVp@WR!4mk6+LGZoipjegBnxbWN=uZ5{&T0QhbGKf;EdDhBqUN?eCm9i`~cO&IqW# zb@nWF>+olFH5J6O5>!4jXH?RMilF|Qn6nsi`a^MNwClR}7Tm&bmOYEzPsg7T%>UgO zv=bk>M-t>KzT>D-OFUVoqeWyPS`N^1K=GzaWzxDdFV}Ai3 zt;SSeAwrd+Si|A$4n|~HpGY|y2gvD9mMBE4XTn^2V5*}l3SVR$ZUkRf{0Z)xT2O8^ z#4`Km9tsd389(F{u;EfU!W$#14$`C=2%jPY$HX|DYH>7oMK8L-rV?SN;Z%z zI`mA7dWaU4T;$L*q9p=)rC}D-B8EZT;DK`f;e zs)K5=ODjNx<6f9w3Za`#C9UttLB6)i&P8%a_inb zy2Gl4E?mHgVh3Urm};r|t-KT&8y*{qwWG`@;8x)5l==E{yc0N$+07!8z3=m>5 z$cdI;7o#kG{eHCKxS|{!#krR%fT0}A%$r_r!mvSJHRP$mKAr_lbfJlHkbFzNis0># zjX>o!76DFT#~pGSa2>6?_C}~dLdKOYrLWR%8SEIDHYWE22x;Vr=Z~`H$;v8zm;UW2 z8bUce*_vKPei+vD5+2Repa51ARPR`5@IM`(6bX3o6W!n^%} z(#T;WKlD(0CY+DQ=6^OeUc4-%klWW86|U!g=LHpD-QRhcrjYxwX_Z@D;~hc>L5mab1U@W{14qvPsSIFXK&>vm4f*PWh^@Yf6{Wp&U?dY%f-D|GU13Jr;W;wPjzf&T0snK1iF zkJKjpsJqccjE_g1qkF_rbA*cNd4r>p{GBmA3|-HqnD4H3Q+E8WhND9-Z*cI_mtCw1 zoOSobiw(JtKr5~FkisK3Gr-&)qD=23F4kNyWp}G zF_@+<{@Z)Q5j3y%!1ZS%Xnr*Jh~7$qYcIhz{E<@{`} zCU_(7*=D@eIvlXE$$n}G*OvGVjub`jORz#-$$8qt594yQNf(8>cgDy%qx|l7aZ}XQ4)nPrOSwSmp}LKsfC8<9i5kR5 zT>eR0$dyUCI+0n1ga6d+RTv3N!N>!cA*3H`z2Et`esT6i{Q@m8G?pQibx1Rx((v^s zKqS>(6Egd=Qm55&o?xRkF(;^coz01Jw14PqzHvGoXYQo z(jX1+o0Qp{Q5&#bm4#2@TlW&Cscg}OM7>y-p?GIoBeKbZhoaP{ z=8CL2(2Cci+K3cDj+5()p6JS>kiL?X6DWoZdDcF|_f^a6+ znyWw&giFq=N-DnpSL|`l=G6J)(c9xwf*$?fGNb_-!AzS_u5N8>p-_T8-3X9JC>ad- zpbuepy#f!ag%~;^!hDI$z{4rxPG`PSntfB0X0eQs$%g)R=S?cg{-j0OS2GTg0HZ-Z zA#=nF^@k!|z2!VP-Kl%F(S6^+NrJ@@aw_uEQcMLJbo@#56WCNlb5P394hdQFDNC*w zs7#;D+Cj3k&nYi7hc5lQglkbi1BSrx|O#tR3{eu`nqZi2}apHJXVJD{!RiQ%-G+?`qkH3H~?Yk%;mGl$qR zKNM8Q(amY}-GaSTy9LiQLKaPJ+%)A}M2J{Vu}jKpG9qS(l>K5`Wm)@jh;}S@M#7 z0js2sz1atuxY~sUGgoVUsHwNvEv%<(E1(dL)lOL3AXrUX0k3A#^Qf)Jqkr5Bdx0id zj)z=7!8aWcI?np@jY92M9|yk|@>$S?H+>P(Iq^3(%3nyM$^#UaZ4@u7a9TK(kD!=Z zm)@va3u8MNQZB-05KI6iOLa)o z4?!OBpjW<+5=JD`X9z6&2ea(&p>Ph0-i#>2jh=ogAb)E)1w%k%TN$^iE9qJ^(UNJ& z!Le=+De<@4vy+G17jQz>Y6MlC`35B`L{%~pVI7gLxz)1_pDu`EW~l*e;UuLJmrRxk z08Pb-QbA~>xTYu$RJIf^X%&dLP)^r^xg_$^5th!Y{ieQ2rzGXoaP>$x(7;^;z=pN- zNLAj*`}cWV^}g z>T=s@cp__ODs<8scCG=HYd9ED)o@dDx1~x6hpfOkE|66Jy3Zy1VTR#N$sufs!<|$v zSnjHl!1QKJl<+dJPNn+99gPq$R&W^t-1QH{mH&rprUDD(l_XiiU-YQ*+PSH}1twHvUWay9r8 z?1DeL&KG8YkFxI}GU&wYZbLR)k5zzFAdZ$M!OL8Y$w z8B(!Ri7tl=oj6?%$!QZCp};(&f^c1bf{KDE8RILVGCM>y%&9NQ5#d%RiCE;ux%!6C z6k2Twh#pk^1Prw;9_t;L_o9tyK?{$Ou4zUU_&}NS&^6{0N$3wfhB86es0>XN_i!9V zsGNu$3&IB_ktO4`0Oql_<C!_Fg63wZ0UnWOc17=B2k~ZLR!Ox>THt?n7?J7HP0;UOjr_7VczUsrD zEF~;W$T+cIuT@7UQ-2to2g4)k?_ueB<*+UGg2FIUQcoQ-HPO&Pd0`NHwKDj<5U84? z{K+uFZK3?P5zZ+NRxLqJeJP1aIa56_u!{o7DuYbZFwSz zuaY%5m&{QqxFBZX%0pHtPOj*nrYuFYZ%_cc0wmHin{f5kM-?a!FNt;}k&eqA+CMDB z;Wi+{v;Z*8j;S1XQd`~DC08Es2V0OHvqADa) zgeKH*a8(MRPq6l;BDATDRZ~cGfUdq(Jw2lKt7LTEJe|>9sG?yym1=N5Q|HX*U$lI2 z)#10!7LEk=l$56k8NmPJ57dtCku-uGkw#@Yn2Isk0;Ow@!Mz4XHU_zj$#3K6DGS8(hsvhdWW%IBE2tV9@dzv$YkkVyhOCy9gm|Mr0It@ zCwO(P7p*n78o}Vk1)aC1IfQx)M}^rf$O={MBSkaigyp=h76vz9b*Jb?5x-No`3Q-5 zAmw0gtXB8i?)b)o6Fsw48k(|P>j1+)Zg^?Xevz!@aepV^(oO^cUXv;KVJU6-m@UXI zC;WiMjsz>#2;j(2vCm6wKF|<45B%{+M6Mu#vVjs&wy7NPJ#|dmNO?jMs#ZXyrd!== zG)KbW6LeG~3E?U_g3M4Yz|5--BP!|P-6J;44N^;IF~_MHFzum9UdEyF{Q zz-sls0$|^vr$+*8I#gT0YMrzNSi&&ClK*iirO(K_1C+s$MK?$Qum1$8Z4Yslw80W4 zml5hcrYPKibV6Vb!b9%hLCK~yPAig$+87QMcBIrSBu;Z&ZrfvvY(huq>y6#jgRZ`8 zz*b;*1Aq1;K~V#)yMi0|sx1t{XgBQ$oZr<0ldr;X?UsM?>PKe}dAOh>V(t=jOijX6<^$(@jFAP_;{1Q7Jao5dK?}+^I2(A(=_`qrJF&riI zSfAY_h^1d34ro9#`aADL}S+oy~~V30OR@{BlHLgk7$fCTw0<#`@OhD zXlN*SKekhZ9zNZS-+@bnUK53WJ+woF9t-d*8Lb6g|JL0hG(a-I2PIm+FNz*12YMds zu>t?dT_H3uT+(nqjw6H~67a7aw8cLBCfp$O+FcfqAK2=z2O~g}Jf0m+K>SHuAoRrC zDp!QH+e7q-07cc9t>97V{?JI*r)P)c){o}>pvMG6sz+^k41Z(34;mD5D9H}}kod<( zkp^i2Tx$03%l_+MFdsr*ndf(=0YAmgRBN3?VvxUipjfa=yf-X(V1s>IyPkA)BG? zbyDG9FLQNO%8P-tYv@g%N!>$v3p89h*=}VAvZnVXhN@k7y-S{UN?kHh>x!LC6vjgU zBd0w@QjfW+q)4H?YE1PhvX485WKVy!uak&$)ffHRArt*Hr$cl*KsHdzDZY*0Ddt0| zCV6*M0u6zCY*N}JChZqzI}CO>i{KdlJo}*2QKm((kQJsMBODlBhC@}EM0zabcqqYi z^(AFtD}0XVaqXO0);qURAE-khe&1nlI`)SCWi%f7vwnvXdZ~1!i|%yFnWun5Xhgkt z00$%*$>p>t$^Q_*EgxCWF<<<#iPJwvve98M8zRL7QYKodQqvrocK(fg2EuMx`a8^{ zNIRB*s0=zm7CIcW%oA(?9Ij1R0UI@DwlvWc~-J5C5T>!q^sPNIf~9tS0w2BlQN`=hL%HNyvB4_C+0b=sUkrb;Zh}nKE)I6Y?KB#Cvys~-(g;~%kfa-dMlsUh z)Zg$a+6_#*N8Iq-$Zalr$!bPv$|zrsSp_E~W8^^S!42g+59=2tk%N#RlaUq52KyK6 zGc;w&zk^6SBq>U0-y8c0eMi}i?Ws;X~eVMv}QwQQw>R$IIrX;d*87{kP zcwxw_-Q&cwxofykkp{OQYUohNbFMHA^8=cR$nXe(adAX~V{AFH5mQJ#u4}N66n3&H zdF4Ci0;gah=!Lx+;`}o!az#SW3*@Lx z)a9c9P%(Z}^=I`gOaKukgw7rk5`1$Ay+7%d~KX4vne;nAGZMKg zNTE(ltp?KS5%}8_)9i5>&z6WYD#xJv{psO>dph%=g~r9~a*p()S#*1sN;b>C#8qEF ziHf8Tna&u(R59qKC@;SO2*4IxST5 zN*Aj6E}9}A+Oje=7xLAIUsd(g3>i1vuPVF1g(ON6@_#OW%5_(tbyd!G3BDA*f!{{d+*3XygowBw-Hnj_WfNUg{kES z)2zn!_V(5_|6MNNS3@P3wh+YD43K)&5EUq>EM9XKCdC4-i&$b|Sb_pHMM?m3MtSv- zRjIk&=q2*G@ZcsgeDR)-;$+3OsvcTwFfZ2|AxRYS&v3?22lj{9=?V|xjeFYchEoyo zx@sB59*BXcWFCGlFc07HeQ#>qeZTW_$~yc@vku>%o*pe@9EQ;>J{r$2_7KSgRYBm5 zso0%`jr)cFQgL6u`$Nnsj4&CTn(8XDUZBJ-RU2wq4(bVpsQfT zROza$5?sh7WIh*>?{<)FYZ4?-_u#rj5l>-OzCeop5W4oAuV0+aeD6x0J~xcZ@12YK zmbs`OUhRL8w9?$1P=-V}f54c7dg`_oyGs4U)250P18O$lW-|FkT%?+PuA^3K z*d2LO(CenU#J}VAsA(DGHG49Qi#wd#tzUCeAo0X*D?q8yaZTy*8CF#q6mcTy^pkOX z{S>&kT=}6}JmDtp(yoSe$fBT$^~up_KG#oH+=5UYaT&fuXz0TFqQ)ciVHG$ zplVc8w8A9lEID0de~arED#)%u%586b{neM-+ft;UU5$dQn8Mxt2{<+JZt36>GI`^< zR3fU_v78K>PLmVJfwijI3VFZcUT6l+aQLZ-G^g3j%}e07{u7#oCqYuf!Gh$HGkNs( zHqD~>Fc*|PN<2d3iNN5GF0H1X8SA9 zOkS^uWonH2NG1&)4aa;f`k2GI1jP{INCjz%AkJ&N71964<}u`hg8;nk<}o}uh!1Gh zn7e4(_?Xf&Qy%k%9r*v6!vMeeni68xp7rYyvdKp94jSHV{y;7rEs!%Ksa9a9_05WC zYW0NKY7D4i(=oCMhZOe9RWU;3IZ^X8 z<>vGROKhwa#%+7%D`?rNn?Y=pQ`)Jc8^#E#la6DCS_Lyy^FS56sAZ-dEv!eSIO zKAfsT@=V64Je2p3B9I#nI9oXU|9s5KyQFZXO zb$2Y#m}=^Z1aH(3s?(sI>eRkmOIdj&KJuJTvzn39_Zm{4rW#V4J zpg3dRxoJyM=0Ob@f@#dj_rPw}HPP;ERfOu*d8J^8pQqB25m?$84bR^U;SPlOmMqQ$^%_#7C@(>I*8{JgR;B zF*XmRhrUB~(k*W9Q#yMQdQ>`meOqw&`kwq2Qcv-}?|hrOdwr+fy>tfPWiDUd2$$n& zbmc?N>74uUE`A+C5#x=IsFW6->GH$)Q)Q5N2d4x4iiel}Xg>BwyWq^O#eXZFqZl`e zyHT`nuLExS1RufWm>s#O!kj9_HF^`k8w@g5{C3J;8&9g#ZTP@l)Zk;!T$D#t`!j}P zJgUoJLJRv`+UjF3K$V&^1n(B-)S2*$&d$zG(X|Us&PYLWjaqLXdo23>7>tt3Vkcmz zg4orAeA9Wly*<4}c<8gI^zX+W_%6g*AU4Y%=}la?q6Oc7?7<_Km1BNAh*y73UENTr zx+9KsDK4u+1Ho_v&>(jLI7L~es>lslky|SX|C{%V-hL1tc8z(twz-)=p)rO^wF--P zoXpg}DL!%~aJQTKuKN}iW*RGWMT2l;J~v4?60uY#;u zODap<%YXmZ|A`&xr?H8Pt4!y$1TaV_1(~>0_^uwx<$}{IEm)PTE@p6AqNL@SN?I?d zQQ(#g;R=hTh~vwGU(RSMyh>{w843?Mph5yj>*eODd(W2Yonbjcme9pL7=$% z7C>i-hib9Uydj*Kk;n(rbh>*#Zs9up3HoOMdpMp`iVQ%V&gw9lQ_Nf~$x#z1Wfg*_ z6^XGj*W6jH)OqSff+MEZg9iqrJxU9Bevho^F5n_4EJuY84Yf7Ee`&q(#;vl9)vXCCY-tO{mKN3c7F7s+LwS6hA=au5_c7)S@}BiA`HO|e#Hm=7|A={wK2x3}By6AVQXsa69c_3#*Qw8m)S_yG8My_@7vWnDq2?UM zA+!IwC2ATByh1LrhKxfy5&A#%9tE*}xrnQ_}dx(E+4X13tn2#*a2)&o@>Qq$$? zE~`a6P9qfcu7WgJ`>F_qnL`^0D_UVXaauz7*uM}>8d)4cBw)ofvUHXEyIvTiXsb17 zpC2xF3(5*~S$bORuLW=<4-G_PYi=UIg^-;69&`^dwu-$=Yl2k3fTR^ZN7jxu*!r6K z^-c6a13>bW{CJ?|u^JR}owWxc@r4;^kyerI-H?n&KDHZPqe!4y-$&Hi5=NK4!@y=X zL%F-Paevz#vLeZW+9`ls4P3_d|7(uQ)f7*sm1|4U*^_PtrW?3ANH?qP$bybr?9Q>w ziFskpw8KH(vk7U`f|+QqW4Iz>w@9yXLE(tl#&Y_*7SGmK$~%<99&3YJdlG~ft3lWF z(*l@^TIfE2If#k6bRxi#a34u$LgalbhuuP}5@6y23#a1%Bw>P!3Q zobMiIn1Y=b=1B+Ms+-aI<^(!jc+$o}GFQ|cN>Zry(yowo;?5aI=rp;6HE9&P&Ovm8 zeI|znhYep8Pjd$kVce|#EI?$fpX+@%^WZ2Gx1mxBBVfhy;2i^hAHK9Pd5cEXGyqup z!e%km;XpZ!4JdEJBj7~k*ey`vRJ$<4G{9*mxY`Ao{HO%L3~_DN_B+tT!X*Plj!~3vQAwP=d#X$1i(8LQwIMbf z-{pUM+T_gt!tDl*H)W~77m`~^fIRcZUM7ifMS!aYh03SR%~rdF5O#^g+%kT1;a}ZC zDr+xmzK>}sROo_TioGk)L>SXx>4^iRs3u$%S3r1l-k`$LN_KDM+JxR~CSlGvT0Ji6 zs-cx1Tn1S)vwACfqzA)KD>_4+mCW$_mRFsbgYk3286ocnIvZrk#f7D7cH!zl<}DQq zimqcE!!q}?ZnCifWyMF>oS&spp*3Pf_#h8$y0z?(FtHl0c0Qz!7Wcv-qdpsp!Ajw_ z-#vN_j=+I$D{8>N@q#=Y$k7=_{7o**VA4{se{f5 zQ)W<$8QfPOU0C2><`pJ07@(;@p1(J~yyhzK-9;jp=|+IwFc60MA^?+IL5Yz9JkR6@;^(NrFc%0VcB+^_}Lb}Ingdek8PoLgNclW`h- zZk{ylhU!RAMWJk0>C>j&ot<&!2*p8ncwXumx+R>LvVPYdkY!|;q< z+)M5Iu&Y>`tvL!$(dpe1j@(wg)BUP7mN?9G%ArTT(^=iid7On(x%T^HuKLWs^sb?u zvF^~NDw9|oM`70w{ekXa)$}GBzo7^z?Z3|L!oJoi6=&CPUKa$m>uyIpv9}!FERrS= zl7j!oA2Yw-b5Ix*pq54u;Ve-yr#i{rXsC9J>=>HZqm(axkr*Lk@>@rZ303DAWXg#i zi(ig}3938Xn<&D4A`Lbn`M8$xWqUdLH;=@+~I6_~Z#pnUg8X3N&|#*r%Gc z+p+YG8P>mc-E zVF6)g-RUyx6+_8Qr6Q2<(T}%AY=hWvrMe}{qMWtg){q0dFk?~WbtjI_lN&HrEN(#r zi*at!aa!yyxn)cPxGRnvl1{LSLeZM#jzutu4WyHS?&P5?79~Tq*ltn?p{JaaRt^rX z^JM#pc;btONzT`~4=~NzI2G(#G2hmvS@dbC1ZVY-o~6eq0&ZQib|AW$gWR)9duo63 zCKudp6sT)9GGwp9B{!5h@9D{*%c#qzc0=3ZxrQp68AJa@oKtdf#EyDO#ie^#0g9w^PbpOkSW^3xMyv&*nI2of zl_pZQg~E-1EC#$*1~w^yC54{a#}yz+_bcQD$|(rEPLWb-F1{ivx3D&d$2u!8xbnQX7 zibv4LlT;-tZ;iz;o}H4D4E`TqQ-TG$f8f^!2_j5z64anXp)rc;h6M?{y<)qU9%={29P@?-?C<&`*TDB4(A)(+m`{7vN=8J7P)lpHeY%xgtdQg|7>JeLP7Eybx zc9nf}}4pu|+ z(k@#dIUo$Bq8P}Knwu`b%q)qPy!=+2jfrGH0~f=u8%XC2=TPiURHY2(d=^b4|8%4@Lvk^buS(Fti>G#`VnTyy>KGr?3Ju#b2e1C^KXXZ-kLR3&$EhaZZe(@F2}8 zuZ@^EO8Fn6_Q!!{&DMrlc4lGa2tZEGV+2!}S1V!`=hDM6D1EWft5m4H&8QO1Ata)S zx|@4|m?hbgnLM^22FzQtG)~GdPo^)MG{jzDM^d$xB{>;hn`hx5e;Yp{5me>IrVA6n zV@j_J&zB42Wd_kf;01K#gcWs-z4k&a4-a4y@`HftuAdH-WRuPzP2r0bapwdlg!5Mu z)Hs24({%MOy#V$IzQ$NS&ZA(ZuBosTcSK#uMaEqTgZ6wq8g3Pr6-Rd(kwSMZ zyOK~>g0D;PdpgQDPWycAh=hF+M+^^DvTo+t$&MRlJH$z`&C<#w?9Wb3ty~AJYP|z z032N|6(Fvb7WJ!Q-3zl=VSl+V#1ruh*uS4j4z%A{*rHTpiduw1m+j3d-BOXHpj_mc zgy0$mKumUbG3_CB!5HKWe&?)J*L$3G(O9TYJVISin?YWz+$zFyO6}Jw*_XqZ$7ykP z=$ewKncEQ;8yX7_4_I9)lB8@1iO5(10qMK~^{~)}r(0qzLqdcnV7@ z61$RQfn3w%?OHJH7t?WDqq~TTnjs>G+9P8OwQtUeTm4}*#U2Gcn=VXZ_$@-V_y}5) za8>F8b^O+q)z}(=mZ|2)*H*)|9gvNw)ygb>v|X;WLU>qqRl+*AS<{dHS$;)}G4IAd zTNTyNg~6@j9<3?}slvhSO!Xa;KnNSUSU$)r9`kKv1{ znK=Par)(CyD_TKgK3I=0CX4zy3k0l%wNgB&_`b7wk|1&+tx!M#YW)u4Sr9gd_?=!9 z_V0&CTyTZ{qwr*YhJ#AF3<-;n-}d!LNQc)SdVhG@3+Lmp`JauA7e5qgMZMM)c+z@N zf7|&XtrzuIT`%gd(b?aqhU2n&QC#SeI4!RGC`}LoaEd>(xGaiZ+f1y*+t2M8oKAV-LP)ZOUbe?;LLAKOmbC0k;8 z-nhT^khf}Qj1NQCL!QamRa)T1@w*xj4!ykjT>WK;j8rj>>&6Q%Zu6Hu{R7T@)G=jl zU_zd9%@%AMcC7dQ{dVv92TB*Q@dB7PpM_3ZtSN;r6pK@&V(M~>LiLw_aP^n*o9Pj> zV0QJFzZ(B+y_MWUf+9SB6eY#}7|LrnRCsuVs>S1TcQE|rmqbqmVNXo>)rqIj2jCD2 zH1|9DyyRF=dAuS$$C(xRvT>%`xAWv8BGsTtkdwbjE0tF=b)8x#nhl_V=W_i+gt0kRM zjP)eCm?3RS^F^^YOWOKj7MC5P)gr;wB9J=1%oV_CxP#zRksB+%e3)hG-dim&RYO}E z;-(0i>fa>WB`4i`n5CAD)N0wLl0(zQnnDH-vqaOsS=ib{8;eiW>C?0s(7amlB0M%V z$RAD(V`jU87Dfv)IOOgt$;%hbT%P~mg#BJkg_&`uKPM_avTi)7*{)r-X+eR}MmM-j z58)|B<=<-~vIRT1lMJZsT2Z+MSoOGq;@QP6iJT+FrS^ic6__&^v;0h6M_QNzPil6h zR`Cll6=fjRO=>jF4!%&=_F8G!mFmao#`TLDSwPon@~oC>z1GDAD4iR=3Y;}z_+GE!=?T7|48*6|EcvI2N5b&L)nJFvMJf*`a==(m0&n^&o;X6JHW0O z$tm^69sd@wFJslTGe#H@9ML=SfbMsSqQe8|B0T&9F6lCguHMbYT>m=z+26hKyrjf5 z42MuqWIq*m6{%ZX_68b^~n;3zj_{1rta1^@_qkN{5ZaTxHqFj>{CeH<^!<049%qr_+-tFY*9!4_+n@ZY>i6ky{R~Rosx?9P+H2Znc!?b5c$mLs-bi7K{SR+Yw z_BOBNf-wp*+mQ)FvN`UJy%;J-&fS+9D*EcKBwkGS3;qFqSnTXYdML!VU5MXfGJ?{u zSKA%&e*gAF-@84h@81s6Yxtu*9=r)K1UVJRd*lhisCAtlk?3}K1I+ZB(-p0G0nBrrcsMdbr#cb1>3%#2-Tl2(mGR9zCU#gibuSH}rN zQW`9^uZgX$(;xX~^NUVTrPGw3&L%t6^Q%qDc20R96_F-6AjMq48Hi?8y;H$u(>a%4 zmcHpvN>fTzTqs~YymJsgPTp_zJ4d!7oHjjk`lTjLf3k(DNpFbXL)N;qJN~Kq~ zMQpAl2V$5cL4r4fjvIWI8K*{+Z;zN4E;EZG?>Z<-PDz9y3~M+$oXaT~!;cuy=LWuW zf%LkNr~h~8@PF!_*}lRDLvw&CCYX|UJHbrr_g6UnWK&XQ$Ps)ui<35T{42(ZyuQR3 zg#~HBao7TfE11;WWx*U5>7k{-EsgcQrKB9DYxp=~zmZiz6GKh$({n>@H&IWD3}KlI zsdEV7hzzS1Fskn7EHp@}qK1zU2x0)J2W1d0BROCY8l7`0&jg2xLC}mmQ0l-&Z#0%R%QkBSMP;J~(}p19x;Mz};!!5;Cd5;#t|;+UqlP9;5eHs2Y8#@^8#N%J zTqMj36^1YU>tI;JAuoHhM%-!@LL)u2Bs9{PE)q}`M=q%Jwn!q^QBj`EJk}=Vg!LA8 zsIL~sfk%$6oX7b(6^9C6UR+%;iu*`0iHLSMI3sMP_Hf{h!x2i}59Gcjm1NV+Bc=1;q|zv5-{HNKxx(L?3SHfJFynEIB+B$jx&h5d zaTWo($6voiaudREt7P&Q&yY&;E!DcBFI1OcK~O7Wj6z%VOvEj?Zd0-vpt+vhqB#BfG+=lKF}cmje+{W&MYxgRu{N+#XDv>6 zJE(=k9FJSU?MIT0)K$?E-$aP;fjFcdv0xzQ@3X0h^%%f z2g%dGtw`irx^ZXBLpeQ;^=?Hij-?EHC>4%1+4U%JY?a+-EzYk;i*o>V2k~62Msc0j ziOwC@jMb*=LO7ma#O&mdP`YVBtxv&HN@Gny%XA}5Um(CW zP>l#Mpch+yl@;NEW@`coO`ti)lull>ecH=N8vqo*h#iNJXQLX)eRZWQ!dIjpNXIfn zyaAXSXrOE`YgN!A=$~?!sz>Hs(L8mPX1cke;^S8L)wTY9K|6tyA-n?2-m}I91G2S+I2!O{g`8RU* zu%)^_Gvl_|w^R>Z1ybqWZ}xWdog5Q?o4(y?xDh=-A*mm)O@1_f_AdblD=AJ(_g(`a&{AK~Vc^)^8J zros?HljaSjfX6X-w>8H%_7!N%BFs?D?RRNe{}k~IK5{^?KU?e$1|*Q~bd<^?P2Z6C zJNU}Kr2;!~&+~Oe!y(7)N<;(v2Vi0C-}|EgWxxA}uJ>_Cqyty;gs&DNYvJ|Gm1Pje zpt|gkDV^hqIgmkm-IMab{rd|)G2X9fFh0AmO9$@gDws(4g7x72_6PQ%h45sWqd*!r z%d=q3j9o;>68wTc+~#nb07oR+q)rW#`xGH z7hMJ}FfKCS!BE6NSyw(JO2Up*G;er`S~gnf zc;H1!d{dItrre=-@9?E_~inWmPiO)QXsCaQ9$4Biz_ zK7ovSd}xq$Hs8Re3=Ln8(h;DFa4!vhYvCdJH-@=^T2-c51-5_DziT9y+@C;9E1eKg zI6#gsi*^=|+2QHYYDer?sYtb!XYu)>z?Qr99WL(f!Os_I`?oxV4|LFLC*MzCEJpQsHO zs`0lz6r|pM&7e7g>ZLYlNKdmq&`@u!(EQ~OuMg8Xvs%bRW?lNh#bwg(Jbk|1>D>gQ zl@kWCd%$d)lK*2)X;fgVD%0I5HUUBX$b|GTDT(sxDm7NCJ$wTn@mm<{ zqO1ATUgQ!wiz@e%+kt8(sJIs4G1ISE5OGFzxFT@S$mBO#jWa?~Ne5x?DQ1s17gKPQ z%^BeP^&LpnVdLc=B3fvMc$9zJfl=u{+`s zT`rEQ)Z>e^2BiV{-0dLDxfMyz@ZpudWgD}5w#1A3yK!^|^%B(|qwIXP?O8f^c;vW^ zomr=+Urws3fu@tjFU9*dP}7~afE&tJhUD~4)=OCH38e&5J<6smMo{wKQRm^3OPE|H z$u#b7ZTX>l6I=yT^6_z_*~J$9+S)_$_D&BrqJAfgq^LO%9Sz}V3z8p35#neNPzYzB z8F`9z24_$zUNLkflbA`&GDKhS8B)QO`Z;N@1v{R&>9cKT+xZjzZ@c4AC=McTM*g{n z+>JfN>3E!fyAx4P5YM^s{VRv^j|HQU^qdYdvz^S5s|6uF5$99uuo1V4aFid&*CBk( z;D4P*lS*A|&{l)NW5kq;+68CB)kA{Ux`5@O`(3X|>K%5ZCsrB+~rgYczwjU*UwxU97lH?&EP* zYYkOz&7UG{2OiD&u$@Cl{P3nt!*)V{2Vd#1oxp_c&~%JmXrzk2L8&8Wgc7j$^wmVEcIXMy8k0iRot4Vki?;<7FkldFc>fxEcLuPHtXssq}xeQUrL}mwCPX5UkX2G@qYf<$v{WxA`KCh|SaAkIpPAkmsUQEGplHi2 z9Sr^O&mCkHl~U~TUjLwq5K0dJ9_XvF(3&qrTJ_>yC?QqBjw(8o+wJ$>hxhS^o+>;X zqVVvBL|v)Q-#~5Sk6t1bb~lh75ja(NR~S|X4KstP8Z%Vaf#d>Ro<#leKKX#T=!wK; zB3Us=2asi+=7#@Vc{$nncP%=DDAq3Y2=7KGU*=-Bg0;kMV|uUSGB=swnnZ z?`$ihsx<3nHuY2WW)2dCZ*eCBzOEt9wGY~oX~z!tL=jr3P%-l-RHA{0AVHdRsevjQ zuTmiqbD|{lteSp_+=w*V?~ZMU@G9Rt!vdV47C2@2SSlPXfsyVdcFdPRE;q~!A9f7ev zH-sd?Iqme!e}Wo{sQ2>y>FJSVu}AFVE*@~s5oa{#6k})6=#J2XtfO=UIZ+~Tf{Li< zsRO-`dY(=qwBA!BVZxD&o#Ev?ylP#rmB$?;z6ScT?%}uf>xeR_8HH>%lvB-PDFf+p z>*@BFUqAnkuhy$aSDpT;Kms!xo|{UG%{~Yw0cE5Iz?B4qjHnDL9A)eavTxuB1t{y| z!{|t##Z!MsRmf4)ia%^YABoolCczLlpGm!-Ce>Z5cZK>K=swrGAItY4GkA-gI0bBz zD8cz6u3GPiV!i1QK&>3z0PNTp23}ekK;2{Tj8E`F!pE9vfM2sjonipXz&5G##~_17 zudYo9MM1n_$gv^@7F)j<&SerHgIb3N3Z>7_^bgxQ>(S{9S)#Udp;)Ll%!L7(UNWD_MB z4KYseEhA5N zKGm0yp7#d5FUDK=N~N>WZr!k-4kzkIiU@))_{{sx1=^m zS#Ka64F|KS3~i18nb%2cge9>YaKCa z)Y+7BegKDTp!!&UdbXxpWKE_KX8>R=uRltRvRXI$3*V6)Y03Y>IE&aYoJ8Mq>#}q)vZ{a`?fHd{#1F%qL)aF%rjE>TUc=!L_kb zimPi;3Zyqcjs3HTOG-x9PfwPpbpHSLzJIxGBgy~&dkO@X+K?BBmhCu+=~B5A|46*C zY^@~6x2IF7KoSxWkpu&Pk`+Z&`x^HG_h9=Z_v!f!U_cTCNXdKoUVS$f0nGGt_w@Ai zPc?HT;Q<6+wp^)d@~k%&nAW?dN(bx+X3Jw+ge1qJEwCmBBVt-kJjB~fsBM}0ADI4O zX5u=pt_ipY>A;#0 z>6QY>hS31!3^NR(!3kIaJ6ibzs)sH3rl172o;_=G6B)KOYc9_l z(6?{;WMSOSb)Mgb=wSWnA0yWuSShUL&*E^l;&3zWVDP8!zRNinqDCAHOx}uZPntcr zh($*0Et5+ikPm8l8TRAo5-knl<@7(keaS}0KiYtRmf>fp1m4-x@(7Av3`scaS-%yES= z=n5zJn=@oBa0@)FR}O(@*cTGf+Y^RaM6gaMn}MWl7+h(`N|7uT^(eXR_3@aGfL2dx zZu|orz}zEO_13YxV^YCd!!Jo=oHFgHmRl0E6+TU-j!Ew$rztYGaZ*awByZVR5T1Ja7Wn1%&X!SYfYS18cnxY z>jp>ML)s>;Iie}~2|?{9&#SB_QAd^BAUs!Vp;_dsW27OV5)(p}_&-G15Bd|WYEM?G zUb#=uEv1xb;&E=-_`VR+R@FleS}Q^$*Knuf{z%hl^ee7`GPa zA9DNCpboqEaSjBHm$(nhY(e32IXZglQ0QA#4oTC|DMg^+yG`$JW9qt`(!ugOyI08} zc5^WJfL1kvAVuvXdkU?|szB40S{7zD%YwK@sKDiZu!HxcU16&23J0%UevK|%>2W(6 zN0*eD`!bs0e}#>`dyLo&q;&NIXba=`jJfN`NJ`qTdxA(`@zo*RBj#5q*hNJ#4}xEr z1J*qYa4CW>esBaIF@?h%urEjM3F3uOI&?}Q?p+aFDQbmJJH2-6n5O*+ZIdbQ&mV9w ze&(a|Klb3PBA*)r@Ev(^M#yK{!@Yk-HdB0l7$PlAtN_<>M6RHU6MMqpL*Kk979IBa zkJ&}C_kMvy?#)Jie9i1Da1`~2yM1cZU|^DJ?gz}QBEwVpLOMW3A|kl~i~s;}63Sp@LqIQ)of70LwRs^gJOG$TR}rD1|2}W&k8C9dA2va1|pee4k#u7B5nm zHlr*GL1PC`GO_5(Ek%$4!?S@Fts?ijTmboZcO_3%$7hCGi$KV{ECG;)EOTy-x=mZl z;Q83o)INx=Opr89IO{O}1MUa2eqb1}xMfX{UTmm91_Y;Q;o+sn4^P_QoEyYZGn-ZR zI;g(6ab1d1hldv|c$yd+M{_QOFS>XT)EU&4gPx&wBhVKtZU>y(;pjXI&v64}hQs2j zSgQ+K8G&@lf>fAPqfLb+9dM>DUrBEJG_saClt8GupajGTD>zJXb6hq9VifES(x8lc zvSIgHd{KW8Y<|r?h;~;N(%_4o9sjnyhJ{hE%v_dIt10KI?2@u|FInzKB*)Uw6hkGwT& zTlR8Hobc8_B}~k4A$WKm3i3?66cWH}cR+Y6i)S`NVWD;h(1$jkYCd zSJof4w#hf(_u|5^L)iGMgQj34Fz_hLcxs1^}BE{CJ7<}yJPt9 z@UhN<5--3v$On4brSXt{F>tlt4mAg+Eowgou>_Z$cYM62!3> z)c9hrqcL}94WIs=cV|u4>(0`bo4h|uKB;Nf-aB~h@cUC$yEeB<@EhVX5hoBWd?KFj zig+5jTaF5r1(&I6Td2{B`y{;1uE&o;y1cUXbSQmsGcP+Kvx!;Y4e284j!2GrIr*x_ zL->WHNu1fb*;+)#PQnc0E0}3GLi3KHlK7oGHp%;PH>jkUo5CZ^1l-AjsPcsQ$eb2x zqfpfCWx&E}7a47Grmxr1F2RD=$uNQNFUEJK^KBuHm3iZoV&G{Q$w8aOc{wCa(LnGr z^Xh2ywfqYoF}Q*A5hb4j=jRFe^xmPwR1{yd9clGhf$N0{Nms8ab315`kD1kJ)0pS8 zHiu=hoUyQLD(7k_Sw(m;4ykJ6G~F}~`K(RhkdM|74x!zmk;h8X z0a`CUy(@{3oxLgCa&8AYXlbi6<|Tr<;+2r!% z)8#ZizGjgiEiRI^mb+}!zxCQtwoZ|Oz-kfF0*i}WomWk7T9Hll(*`(H4_1{mU$PoT z2rjBxL=@bkXGJ(O+4P$!8fqor&~#1aXInvry_+E>Am)LE%&&=%DKZ@5!gB^oy@)=c zEHuHp4iXU(>eq>N1_PPk20Mj*qwh~pk(06;ksFtw=BwwR1f&zDI+LAZ@Q^6SqVSj~ zQTHKAkRM>OEHGEmR>1XL~D#{A+XtAKED6H%mc4UeYGgg%* zoO_nL(u*nJ_M#(bLpPuciDXzpS;&N?3hjcBARUs7JPPK~7s3J(6jioqYfF*Q3n-ga zvd9V-N`3E__Ks>gyu@+2wIY+6x*n6C#(6myE9}@6=m3Kg#5}X8C{PRm-10jY9Tc-c zu>+FvtJt}4du35PWJVGBb-23GPcr;N=hmfOA`6ePc!6+-A_ink3u4pwZU*|g)PNC5 z)BP7CBxb=t&#RD$hJKieXKBhBLYa4|g|F=VCnO6m&oJ>ATvRzch`X*}W)x~8yDl3_ zJ6=?zjDuVqig6U{B&#mqbFq?JM03el;;uX%9bJ3b3LJyP3SF3mP9Tvb%vXkx&60QS>t&Mk+9bpWKet8B{$ukMm%ji;j3R_?i6t7?tVT)RtNI^wm6g z2#X|c2(9ZncM7W$lVumTq{6nMwwOoq`p<*Rsxe*FLxDWdI9wCD?NV?L&IVQ&+VPPf zNGAa25r=LcR7nC&rs!98f?rc6>THBUjuhzwn@Pucg<@DVo_s=u1)&*Hq6p5N3>)yl z#0c~rGpeKN-4Km9&W9oyFN__?VRGkQ@6UQ@ueg?DsE`FwJdSd&G$4JDgUM4bP=$+f zFRGqThy55B;gm2eHS&Izxg)Zyh};r72@P<{2UsXXtj1imgj2o*XeWcK|E&BTzu?~<4_j#c$!{&wA-CzHYH~`M1yoIF{#7fh9!0dJ6jdIrGfU1nl3YF zZ@_w4igrGB2JMq5i);SMlDNK${JpUyfA8S6E(tUUcJPW!-Mdt&d+%{dp(Eq`OgUb{ z@D)`rWO|7^Mlc#HBPnxX+%!l={_en^f|>6@sUS~5sEt;#f)5?v(&$)Bq|2_1U!~_~ zf7!keDPXu=BT1fDEF$w&bafQ%$@lG$brj@l$d4%|E4jS1t>vF9r0{KHBcNNG!uBl`052IibesW&ZRRDd8#Yt3E+5GF_`*(|P z09nX8zb4V7y4KGJIhBw?;iqxdpy+1~-n^b~KCDTCBRb$6lm%obypEbKxki~Y^Fy>c z4&`L}aAIDcCT~eno=80=$HeN8#fuEPqv)&5X|RKr z(Y6p~pI7^2mFn;lcrS0RgAh-YW zmr6h*n1jPT2i6Z0|Gq%GZ9uCmrw0f#43cU@pPs@Ji?3`Xme1@2%}-kkHF7FD+2qp< zk#h6bC61h90R#r(r_)`*)s%IK$bgENpQ6r<*m7b3D-nvXS?N)PrXE3x)0SYS_@YUs z0$8=_RGe>lz%=!!Xf`j#g!rsVgp*$~*_c{LmVLoSEcpgW>2$Xao#aRy7%L*OuNbtE z4;U0R$s)&E9u7^4I2f_*laP@UO~NWsLw!s|qv&f3K??8KXrf+{P}Cud8cafErA*;1 zgE;D$0H-E>)NmC6DpKjqfJ3wrl}^Kf0ALQ8^h@*Tq~K_RPI}6@gwn5BC?x@Eh*Em4 zWkJ%kN&-Lb51EcwiA?-E3u*WR8#&CW>QI7@V_hnLWMJHwvnH|^&uSnQLA?k!SV>Az zC?9<*cb^T#xmT>n&Vf)1;ko(jsL#D*5+MsqT|(q0S`L~#apV@P#`J7zz1>P_qhBef zje?*)Y4mh+kfC2HkVb;i2xas<%K@V)bAJj6@>qC%dCnQMc|-H?tmQ@%e!nL3yNLP^ zcM$a8qh2O{@}J*`8!j)hb#mL4Kk(vOC%3i|f+2!{G5P6;nsmBe+P)3Yg%JJNTCTcQ z@@IP5QD)j>a~dk+Mbm-qxL?aB93uAHNq33&soobW2zGLNVgq_q4)jdlhS^DDU@NwR zO~B;=mH@E-(o!s72gU-6@7utR3t-=RX>^WitPE7cAOc^8=;@wucC>=R2wvue9P|9y z7ykcmU-%w(Vtu^a`#R^u8aCp@%4Hv#7O+A9t@*H~#s82gk>sYLbPYr2QWsXE4<`!< zo|oCgq^C7`C_A>WSdvW2WIS={yPPHeK+AYCiF43d*cwT2Ps?}YDwyjMb7#V%RCbiI zF-xaWCOv}*?h4C$m|Gqf{PmW{$EdbEzA9@tH%=*$ZnXuIaEg2ZM8~M~wfR{Vb8?|n z6*)6a&6Le8eQe1VVy67pznv)3W+=v&WX+R6a4M||=6BRyV@XKpsYa>5gYfJOjnC0d zm%V|K80cQW4>*dyM{PceZAHpAoz(glsPwwFd@lSk%UV($q>j7hUNIaN`H~F9nfP9u zlRmiYCX>*tb(iIonw$_Zw9?!zl)$0(pb_Y-_Ti!|MNVR|NptbB=4O}EKmp218orI1 z*^15JAjesp0m?atqc+E-P4SLFx3zK)-+at7^p-2k*+a;H<4*X;n18Jt)D#|yJk+?* zubfYjk^1rmV|oqc(VdY5tH^h@r5x^j z$^ptO{WI6KtO&6z@E&Mh7J{h#cV`ON9H5#!Nv&j}lpTKev1lYkz>LEU60!JvS7LJw zI@+AsHn_dlfu`aSJh$EgCqk2IToJVfp*P5bR-I-paQA=mfpcPfM51=)uh6ggBfl4b-OoG%4l@~rAW6+dVSeRf9I-#0FIx|ZYLiL_p?3&DL zW%D$7TBtdUHOnokyhRXF>b-eu{>=42wMK=D+Iw&<<~IeWq=i&k?#>2R3R07YubM>B zXRh|AUKeOG&N&-HOC+vA^UFh`w9HNIWQ)?5hp7^FipT7R6}~ypZ;Ior3d|h1?wIEc z`fiHrn#WL)?>-0hPBDd&TeZ)XHR^V#Qo@RsXrrHmU&h@i@zu0)rzTjVa;M{c7HD^Q zU@|moz}Q#7s$6t~cQ83eX3_K1ySa=07g6sFWMpW{mv;}0e3EL47*aL4d;P8e(mGCC zgFs6ucoHb%h%*jb`BX`*H7a<8xz=&iX3!%y^BfIN0#yk;#gq1qG&~FR8{@gT3XBD? zJLWorz#HSc=22ASyw6F;Gd5@K!(|Oh-l2#_&)e^07=OW{0Jm|_YIk$KC2OSE+!&o~ zOuYe)dr+q%^nt`6$2ge%JwS7^H3H=gL5J^VM$(lmhDoIW0YT41( zpsL9UcuAxZMNPiM*Jx8*8qm|MlQb#o=SKdyIK^p3^dDQ zq4qdn24>RXoZdx-;G~sJRjDY7#3&{`wr0G06f=oe*nK#YEn!V^#rXYT0BU z^)itVYAH7?uh&iKXyr4lL0?mOuEqMtCCb}E@G>eu1B%?j37g!<^YLNR@D_rX!N+H= z?af1vWu5mRV6L1zYTw?O8n_s?CJ*j;w3}u?lI{4rG_=1m2}Rc3|fjWbZP07_isfgqw-97&kxi}_)DA44%U#Fe1|A|;%{`j@) zIVpNuqCZ}jJ(qvDC?1VX(+`s5Con1sNT=cCJlj;j^LalBY5*PXh~DJ}s~r0$$H|Eo zwc4$lTW{h85J~K@82DX4yX~c)`mK;!NmDOUIjMeTph&!QLlaIi6MmVbQOwgqs3q=n0GSD!tH&;s2mYTR zURZNIE0WOKp|J1eP`X(;E;pyB^1n<;XRd-J2HZ(7!U+MS*#SReI$QF`AJ8!y?d!aF zpwE~%r zfOPttKqn%=T>xzf^r718TVj_E9B^^aaZu&|Y&LSPh_u(y%(?Q>hyx$7L!1$fA(y?K zIG3T1RvZz?8au-%Nf}zJA$6Z_Jcw!;M=8jvq||~vz;z1#RTJC59B%~_zd0jheHDYd z6R4lSEeFk!GSJKJ4~|Wa$vF6J1_d*5h=l`xK${~51IMHfV=N#aJ<6=yYBg<4fW|6Z z%?W@jr>u@z<>LbZs1r?`Gd~>7;>twC%n6Eh@&%tplT$IyVzL5@#K~F(rw&7fV~CTM zW`X)?nP&xZ%T*_AL-a=>F6dIcp?&m7QlB9gIP=@??r=a+Htfx`kTpAY%`}9DAu4RIDGy%NTw)ki}rPi(;vl;Cd$rWjcRs(qv1~Za1S1CfAjs5@4ofG;?wR! z5B({++g<`IOxGRx@i|F!lyAG4cbFB)Ee8FMg=DAOqyfzeB!5e(j)LCYBI5`|VSj=w zD2NO}7LL)KXmrikBAEvL@GJzK_=_vj1pG80zF=*comNtpC^X)w9Ish&EJcRQ{3{TG zPO~&hvB}5;z&D_>6VMhwSCQxnSO;Ag?#^%NTEKP3Z4N%a!TVD+howP*-#L`XZ8DP<@F=!$|To)vNwxs(PEuf@ZZ)Tgy2s? zI=G3MpR^40r0FlKt6SjiI=IdG{o$AhVypq1mrhHe z8<|fqS&ojY<6j=Yj>9N{OF3f%x}_|^3?1ia2zfL1ujv2)(~#oKk9+8SoM9l4^dy6b z4s#_vVtKNpmb|-%)eWG*>bB zs2vU(c5+56A^D75`@(REGIF5VBe;Lm3OXf#zvo)Ar>xtsh6|q#c016hgyThU zjs14%k7j`<3>I9l1|9Zak3EvFK&(L0K4h|`xJ~)c#420x{gB-#GopLIZxGH9M>{n^ z)Iz@OMB>*H)7u2@Iu+kHZ$eptLIymQlmy^vu>d8FS+3TUEf8i*nnJmdxU}B8=I$5L z@F|>4$zv`a=YI1#BBe#?_9g{OY(ZrA=$x_7kio()PfIHjrl(}_or$Kx)hRa_r%F!p zEaFshCz*>YG3l|zP4TX`lAg5E@@P7?CORKU1Xx^KYuoq6nG6)pKX(CM0`Lsy905!0 zKuc)11;-XCQ_)%gF=LpgwewrZo-xdDBgiUg;o!dUhRoGThk4qoZljmXXcEQOyl1R7 zZ<#W2uE|a=Q!FdtTZ(N+#}V8gqA@O+glKipj+h^j=><$% zSi%x>V`YoNdv#eu#`-XO zb7>D@w5~Xiv@VPe@j&CRARCVG8SV5qU_IK^LP-`NsDE;ibR3wcgYh)I z_Ljb?-QaREh{m^wwSuW5$=xuSJ(Ayfl&P^{A%bu!sW)d&n#0F6dE)S~gS*ICcwY5% z`C-<-2vS3Rnaeo?Ra(As_BE92zG>oL4hPI# z$v$lu8+zc{c;PFnj-35jZxr_72OUgtzpug{NPoeXr}E3jP?H;XHOxq;pkw$DFfc%n zq5<(Tfr0f}I1yn4sE#mL7AJk!$p60dHrZSg*paP zuLJyDhJE~Z25k<`o0s8vNQUh9{lK3%hqSX2CyJdHFW-51IfX_u!iApu(ebrS8=Q##2T~HJ#*_hK~y#ifh#==uyoh;{%IRAVExnt$2LA`0>rM zX9vyF>7R#9FgC}Gi_thM7ZE?-GJ&XorEgCR?lbzLLCD#7%fY^;xOGBVY3%w{F?OA^ zi;i0V6zt$F8MXdGMXi4fdi%2kfj%T7W)O&75t}Mv&!(MTyLIed`qOamGDzWGPk4-Z zvKRG$Wql)+R!Dcu9=IyL(+oF-i?TBaNCMq**T=_jkPeH3FnQ3CVaU(jhuhoJPj1(J z^pO5bhAqVN45LBPy~)HE>5&2!pnAijML7uMtMC!k)N(&e5p){JKwVfFQoq+tJ&Hu_ ziV$2Mk*~0b!Y_6>>%s4;M{cv2+F)mdSlvm-hnqRRP_f1i`aVc=EIqu6{i%A`f~giF zu=VU&o5z;GYBG(3OZaXkP;%QheF~A;?h13Rc(@JA3_ad??Acet0erz?uy7bYW1~EV zU4(u0{j(lijTijaC%LhoVC-}o^W!iCVz$X(==b8;G;JYHA)UqW>hLeW=kc*$ju8(4 zzf|jnJda%$=LkgzxS$97y*tLD@v)987B2vqe4wXYg3ra-?rLB_plJ(vCmzU#lfXMZ z-u9lHAgc{w&;lFE-mUPgTkH#5SZCzHL0t4L8|jdTQhxoLzYpuD8A|!0kx)t@ zvZRSBvqSRN2J>Ofa{$Etm0}RJb)iK4HRtRk{Hy9Bk&SXX5IY~qi(>j^bA+^`aTi`H z#79Q#LdXmyq|o^TgkiwHO0fkn7m;HMiHEo@rp#W{LsSy?XF)v(XaI7rGk2vk#bFph z6BNJ0a1NV#;&ESBZte-i%A z++iL~h5WEf%t~%@1~cAa*UQ-sIJ8C z$KfT!IQzQVc9`-nPn$u59&B|y7)x0K5o=O1N)?R5qJkk52d!aTK&K!j0&ET`+`S=_ z=w+B*gH^ky9%U-y_Ymg{3_0C%`XQpg;~?&S@?Q8;96x^d!lMiq3KZ>r@Lq}AZ1C22-A@Y`7 z=4>iRPM{AuiS$vs_;X8zsX#F@u&V_Jd&x)Ws`^fP%QG|Mc#?cg+nvEGf7^mQgCK*h zZi8qGk>m?U$3D@+W;RXjfyI6^hmW?%JPVxH0vgBe5Jp&uO8!?JEcCfNP(!M}>kLY} zoJ5NnRsT?DSZSnE!|EUE42zIKity8D)j!l3_MC}L1*`nC&XDByRRi)r>I^5dDAbVp zhdRUlDh>rTEPmKR)H@;!Yw`YwoiJ)t`DYzaNzJ7#DfW~6v(}L6%+tftPg@i*OuAPM zk%gN$J3)<+Gkd>pXd+wGm;Mx%K?%yYC7=yJWJ)buh#g_Zj6bCp$3vKAnE^6ov@DGePiq z$A_+U{d+#Yx_x8+cK_42Pcq*I+xrifocCxpfFfkfd;a?U`z62q^|!r8nQwz0;b%JvKlJt=WQH8?zFhX(-`)nh*>4Yj zeo~nC*8A<%;ZfmdJ2>CG`*4&QlIAFUizI7c!t(Rglm1@|Kig;8|NC3)H-r9H=l$!# zx3}J>Zx4Pc{(O7Ve)ew<9{f9Q|FgIs?7{en*cT+^?64G>t#2Paebm_wzWw(5r{6v8 K{F=a$IQ>6LKI@?X literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-6292.0e668979.js.map b/priv/static/adminfe/static/js/chunk-6292.0e668979.js.map new file mode 100644 index 0000000000000000000000000000000000000000..ecc2a300373be0bf645cb4ccb1d80e949f81bfe4 GIT binary patch literal 689117 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-7c6b.c306c730.js b/priv/static/adminfe/static/js/chunk-7c6b.c306c730.js new file mode 100644 index 0000000000000000000000000000000000000000..24d1d447a55c29cfd7bbb909753650a8888604b3 GIT binary patch literal 7947 zcmdT}Yj@kW8UDUsp`hMIHXtJD{N@VqzByA)ZHUxt@_QLy;pZ!*t{=?!BaKFsERSXA=do6Sgk zUS$`-i}-Ls=5+Jbn|v89t1MO`&pb{Q75;`)l8>Y+MXboN2un}-$7@!OvZ?S$KF%k^ zr*bO7%*%Yr^x*YB|M4D!r5R*C&8M4$Db`B%Hzik9nQh7{)SJ7t0uHH)?O(?%AM9Jk#6%n$f zB3lc^@usxX>|TV>jIFqt5tp1PZX~@DEX~h;5K=5s9zB|LRu5low=~XIMWuKWZO*v* zhAnvdqe#^GuAL)ej*zdoyij>@LMG#JaYZ8X7ySo1)^B!~lEkhd)9KVmIgr4Ihf+c3 zkQGIk@U@8fmZmvNM0U0-!tUN%XF-vnThl`Mpw%`0TdMRi$OkR9Dj3uyuw3O;rlD-u z=Wn{^CPEfW#pfRRlH`OrJjDGu9gxQ`9Z z1P5fR(L27%*Zf;YMiAdBt|=e3yJ_}?hI~_yZ~qicOUwYfT3YTHv7^IZdB#gHq618C zllrK%7Qm}j>j%M%dv&+a-p!|_=X)|_;fj?PUVSVh?)h-ja-<9!kF6h%^t{WG70o=4 z`_A>uav)u8KTPA`uRc0mvRVI?fk7syYYU-5UV~`9kKKt zL5x*$I(dG)z#&|0omgiAB8)L&`WaQ>&Pmu4(D9~*76%a?+`tC^*nsd^-R$UL z)Zg?Fo2oJ3i;Wvhd_1#7Sry77b|!K1js`1_u>Fo(czXR(WCCg6$Ss^ajiBg?OUcf- zw^7#x;-jqM7$XEOX2$gtY-tH3Eup{TnSvK;k@|3_lNVh}CeLeycBS*O%*%bUWwlrd zr5XF$OtU)-jHZt!wfZk2jVIw*Lh2oLoXiW)M}XlptJ0LtW)pfykLcv-d=7zr&ET5g z$Zj=@On6PNJ?*QMm1oroc1psR0wQauqmB-D0JQ~uD(XR$A5qSDtSzN zpT^U-i(h!GyfkFKm(zw;b?`D|Qt;yg8{c22T+@mQ44q1zF2mFK!v|H<5~35aCUm3o zy@CA*o=*s!LCzY{_Eh3m*Hx{{);ZJn=h|N}m5i(jH|)bq zAt-nD;c2j_l*+TAV%Da>ZWSn96%d+dIxma(qUA4~43Vr&aD!Al)(~rhkn|xy|0jl9 z2^c?uBKmJoq?IHl0BM7M%0}*oJiY-4yKl#@aBz>CMFhYMq1kJ%GjuIjz;%(j-&i|S zr-hHT)dk{vo7?W(B&1z?=hS4B4jo`~Vya;P&y*@rT&-PQy#MGZk>~kkVA2iI^|KNR zg>;{YH{ef6Tp^ULuo47EVeE*6fMi)z>#{X$B2|HW$|I)`xi7I)%_|s(>SP7eP~EJ-oD%hLbRYI2OCz0`wtzODEq*8bD)v z801n*e=HOkT8tp8RttD}vvwu2XiTN}Rb$(94<}^B6H%?OwOp|jY_vU&ld6ksZIW)Y zD!s64Hp)ERKG7KK7U&-bkRC{m(AQf*iIYne@(h|T^js2sV;@c@7f|>&a!en?J%DL? zx-K@F13`hnVxZ|oNIe?p_sww@DU11eo+fA^`+U@MU+Jl++)d46*IDfB|HMFMIKvd+ zy~a=Q=1q_!h`hI<+UWftV4GDa9dE<7o#)`)h1f>WnsYME(G@TAT$!9Pc+_zglxsqJ z8@S=|!^TQebYH58Sr+pYVfEHX>iocBUX%ij#x>yV?b@b@TlX{5?0y3Xh)qHQxuRh& zsuXQ!%*wgjr|KXB7rpFl3%pLP zZ7tEUI~p~Kt@h#2yxj%-4w-ep*(21xez4S*m;1DBW@y=SA0By%&T?>e_L%l(p*FMi za_YU3kVKpCj-Lr!Y@x71CFAeppkZ=(n`}RY-SK4Xx`e*MCjz#T*aK-~V;iv!#x(91s<6bDLaq4;Nmz!jYPw~tZ+da#B(>`WD2*~HbakX#a?{PW zHAzQCzn!vxK+W#ulfFq>Bc+*gZ@bl3uOETAyO$b7kS^@_z;=J!QO$o0zD>W>YiJa1 z!r=kBMR(mezOtdzT=TcP_hId)3zS^LYhTYoZ3}!Cc>C8}qqZODf^H=N^!9cOGj+jj zPoU1#2<3C!quUE|b4#v&;f_1Z3v>G6>FH9W_$-A_YWyl(SDYLxe0VhZVj72tNeI_+ zOZA0lOT?Q#AU9u*zrVg%;FE>@ZXB{L)dM?gwW7y=c=F_vk<6mg>@Y=8b;^mAr0t-S8w~5Veg)xClQFqG1^OBU}q5Xdmh* zq7?0|VHk`;p1vOio&NdHQ5>Cis4JP0?P>M9gYhVAW6*gx`YAXKJMW|R=z=E2`(b=J z>JMfRu2fFAGQ8k&L_87a(#tf`ZMQ$}3G#Ln z4}wvP@OHz|MZZnmtxi7;2OZ+rjL8lXjTXdBq2@YJ34ph6nu4=G~l-RX3RtQDD6j5@podqCauiA<>YTMXg#V zh>7MViL*&ph(%-;5fil>PGo8@8Vy;**5Kod{#B992jfT4i1})bA)GFn1?qSJQwl2+ zJ4v+C?YBen+Yb3c@k*V62pY%52x>Nc`0Yk?7lS+eEH4w8%W+8Dz+vI996VtVouCz7 z^gC@90*kkJMslH%ai`Dh6Ntf(l^2Xh{j)yEMN=Do-x@^|jw!?7>V-JF8f`J|4{3IP zD6m0LLNdAn@qZ}boG85r1B@%0+ql&qgzYyVfTcXfh|7=+=8V~*Ufc}X@5V6)3HT|& zERKdjFOEh?4m7m~ZB4>sn$;he#%A*@V!1b)nlPG>3W$oE6fT=R2)YSrQ@m_~@Tl2} zV+;Z4)~Gq?jL)N96ZjBh5naL|h1t{`8m?WOa%cc_*xcM~Zl*_4)Yg%m=u|J`W<0v? zgfIK?=%;)H19Uk^XlfSGRvJ+Z)0)QQ5VoBjpCQabciL5;ikUj-U&%p4zjloG(N8RBX{gO;00?j zaahAOi5A?cYJQiYZwewV65U&7<5eLM=4*#B1qTQfwLC)u)LXOIUkFn$a^HW>qh%&vn(0hV9j5emZiWpJ zDXQ*IH1${Rcx#jma8JcH$HJ1Lfu+qvQ)3oHge+u{Y@Klxu4v{#n!scKDL4FF=vU!x zuo;r)p-dpl5n;99G-TP#gc(Y#~`N-R*el;ac#iBdTrcB%lXFqG_f zKD+@4I{3?OBrLpQ27hL31$d?JzZWVJBpc`f-rD3Ojgw;KdJk_@59C@n7r{nA)<@6 zjMdV7c&zvVfhP*px+y~bAh7%U!Yjm8^9RzlzRwe%qKBgVk$-@h^QWJ~njyCL{tryf zZq5H#$8@BW=VannM}U4QVWv|r>{e@!UijTQ0X?r$1SO|s4D@FoE>UYw(Ear70g(c+ zQ8>Tm3I2fL1fS&2xOqs!1c(^o5$kN9XR@NN#8YG%;f$(v(Ik1oc}=W=X9hWq`_S6mzk}B9(^n+-V@mwScOgD@L0Av@4ogNv-R5hfO?Uw37#NaY*uu^F(Mw|X z*{ecCUF^*-Nb{F9s~CnHbCQW`VjX0#=hYV59VeL=L{hnW%$C&=bAfjRfZ0D_nlxgt zKl}cU5(*J+)lsalx+y1ostR}S7}8LB4EYrKFKb;LPP)3%;qQeM0wZx3$(e3G?@LX^ z-2G%CGTd~XBqLd`Zb_KDE4*=iFf+UX$#q?H^S#mo8ltMi>Sr$E z-)kh!>+1Dlc)6ZU<0WlK2>U3uhqOh?WLwfGNV+zm3Y3WUcdK^^ivq=B;eMAaCQTPv zkB0l?a$2t2lKD)oMRj8Vxp_r-LzPB`CDrD%SKI>;*J(;|4x%#_-?=2juR=uO(ugJp zQJbFIpdL}$uEZ7g{U2ueegGT(Z914Ezc5o*cLZ}z&4^9x#zfuDUBTQyMp?nROM^Lu zgCx!NO?W{>>sH+?J3GO4=O$QKYX3l!1qWiz77x?e0<{`3A{G5u^o8;Wbo%8xGRXSD z!Wo3ouWJ|tUFZ9cL^~8dBTXis#gsX}B93tQBp15WWP+fxQ)^F$Ol5&-9#7?ua(>7( zlL$e~`D4q3OwwupYx9R#rE&qE+pW##xRsX~4Ur^@Y0hS3Ml*@bOE}ABMhao`lEJ6{ z(q!`^6UCYK!a22nHe<+-OfC8?Bj}WC@@VKNKQ6Z5kflg!Nyc< zmLQkqufIR1MB@bsxCO;3=7(zmxqK>ur!HkXz-7Yr<AQQk*d*CxJU9%Hm@)T%&0Xe{POO$ijVg5Zzq@WK3Ofx4MG-02(AWGa1T zU#lR~MiuwNgPFw~;qTA$BPK9kq!iL~L<-rQKdpV8@Pg!_&eYt54RtkHFS*wa)!#t% z9%0r|Dm|jf>W4hJ{vzwH@q zANc{phny(5h#^1%wNQzWCXKX^2BBG0DnFn@iIG~zw+{XSBZ%$Qor*Y$B zywSQC_b!Xyw{}iTt?lwo>-+6;>0^wMdh(%0d$ZW8!~uv&F!Y8YjyVjyJ@0JX!v4{*iAk_HbWXPHlHePm6na%d^yM{qaZh;>Te)8V`G3v$eX?jwUOG z8)qZ5(lDFrMcQl*B5YtcmTn6lX!OPA3NC=CIa%eOn17Z>t1G%AUvl@}SJu|nPSy%K zp|RvOmT)%%E4JfkpDzb1Hb_s$qfx&%MX9h`6r4rgU~ViG`n}3cV~O`~8%q@?B`?v!$Zqm_$L5kB2NK5}8HE82%)Q=#hah5K2OdIZ=@>m6O7z zBX4V6kW8D8ra)u7X;0>$8}KlQdHOFjmXb|ALO*c*3G!=VcT z8~6ZFCiFNCp|I=`BJYW}(hb|uxVz$2ypiY(Mb`Isz)gF+hccN{H_cgqkw)Lp5uTQ&S9d!$&dE|G(;b@-wr^A6%R7~Fa3C_P#* zfu=vLMj)A_1u0TmNRB!*r-I6mO#{DNK7uAUTj$`h(xJ4IlX@t@{9j1diD*n{xPR8p zePTy;=3~Bat>mn5<--lB2?Y)vd&SXBWM(})jJ8QJX?5ysZCp!N#dhfJNg-XH3QPLj z#5B119~EYxF^SV@jG*M6T1MXug$q0m(AnaZg2#uLaT~-fqy`YZ!p}`y$lE6gTaqwB ztVwjnU0Qyy)zhqJnFw_QNU$fQIiBp4L2`r7UGsf}q8Imcs+x{Da~oT*O`ADuCPoAI zAV!Oj3_TRTEu(m3+J02V)6(YFBbP*;$~0w2`IF>i>jf4U9~EaYKqp)}gBJG~dA2Vt z-_6a8fE9W(Kt2BN5VR@9fa@z+$(jlvH(|Il*!b7z2KeGXLoHce2=2ea%-ONCUYE7< z9WwGqv~qB74cT&o5anv3;Jo7?K0IFiaD%rT5C%0GVcuEKE+ee+gf*R3lb$FfEGF0IBt(8d0ylgxA4APOv@ZOZ%x?HlC3AFV3NGt2N)45Fl0Mu zopyrqfeZcH+mkhS&C^|jyKm^!1>mXpnbqWG`3qHvN5kY*l&?{fU5&Qsz&=dV+gV~F zvOa|LBJNpim7!4bOJUYsPABJK%-dQuIMd$P*r>j^2E01$_ znVBZggPZ8n6j8U09&Ij2K7P$R5eK~(YvdnJ8odVIJfrt)yc^x5C`=8!#kNL-*S0VS z>uuiIu-^rq;y0zzhWy`s(Prb6UxlJVARKPsEf{^n^JDy^6|^q!h9145)E{2Yn2z^V zxZuc6ev)()^(~igO3vG(=zc)z+mm-KAJDs&dmrNmjinzwJ$_GZFL%?22VvO7=3j4aJlBS#CVR{8Tdu5mx3`ZsFi7@0Qc!a? zb#xfu+GQzAgszjjB_DQ;{>EE5pi#ORZE8(GcWoL=7B-+$x$oSgC9-&Oc5XIOV>A2; z;-lnsMrJzM-+8=|!uEK>vSy*?aI0)O`!orw()Vu0Zp;^QYIkJjGMk__&k*W=rq#@T z0u!4`6qx3OO7hgl1Cr*f?F2xmc<47&%N7E|9XQm?0Ad2i6cp)L6pVEhP77&zY+nW# z+a9SvspNY}3#R4HJdxz3RPs-J@BV3GdUGIwmdO&?WNngKQge{iq?BMyChF0ee%4I{ zqRFwkgrAX{_==Nz5+P)>&vXwj(!<-IDXDjZM4gt@iL^={ZBX99w}bg~c=gwo}K?o(l5K^A15 z;Xv*dq|-8B1(%Kw|Iqj}fwBs)eClVus1t6=ai6 zE3`I@4i3UtcuLykQ!M;d3p_eBmhN65PG+0bF5IS7_}a^3X;R%Za;^>{6g)F&wx0 zn@xviX$#qfmP@0}I%zt2p$}p*Ys!gK+@Ki?Ml`_U1DdNzAi7jW4}UeYGZ`og=nnH z#u?-_v!cUge32J8VbT1XNnYY`=ZT^zpH(!oPOS&$tuec_(Bzy2XDV{0V7X7PB2%m@ zyNzZ|nX4a;Pv*-$MY)k!k~U2(W-W8;U|IaiQCLD9+cR!WUDsDw9GQd+`+2lgz(p4w?7GA z=w~d2YVty1lY)Z2hw@IpUn$R(0G@c+?6LI7<_tCZc1WILeTqW;@T2<)M4UZwa2i7( z$7ZP;xqBXeI}(Rv={u*yfO(vn#)|dm_=CQBV_01|DVg}S%8*w1cFo)Ss~ZWUGtYE5 z@ev{%Uc19cs=-wdjgcpI~XQo$GraIY$Budb|kku6PU>`ey2%)jvRac`GI66twgqtKe9KXTgmBbin z%B@4jE#4K1!?bW0p(UiRV!C0T0MDi*9-nrj5lNdrr#YJ*BjvPrf@UKuL%eZ-=~9B@ zmZLmjCu<|Gc_W)c6&VL5p^U{FgRRr2YF8<37bq!@@nhb=aImQ9j^U&f=CPXKC{YuQ znYIc)^H>n8LY(ue8umg**NjpnwPv-Yx*|;9@I0na$Ya9Rz7#1Of~t+VXy>q#P$*h5 zx=Dbph9pFXJiMJ2kC1>7(l-9_At?Ut7k?`ke<*$Pm*sCCtbDiLXl(2~`A74gH-Fsz zPw`~^Z^@98)hCtYu6S}&F6?aHCM_pxPcWjIjX3!)U$ z39eBVb;8d-3LzI^bbc|ac-uPz)ASMFc#Y1k`CUc$e8odXZH2|taC8-hJ)Or72E1q* zS3FsR&>p;Qfv=8Mye(8b-sU6s5079E)OQrIU`lyF7Mcv1RQk*JRV!X6JR2!o{){XL zeFV7LGzi*s#t~JgX-ffzcck7(GYAyY!}7PP1gs4 z5MM7_)tH5>VlxPo#z(GfX@|h{X{!~ZB7XLuL4NRN8ZT%O5Ys%S)ad)Kw{=y}ry$NmKdrCgjkR$#Pjr|v#tA4~9&pV96$w1neM zQ{y)s?>4w*xTfc&oRc{fKM)_&>4}3TQZcg7@MMBVLZus)(mrT8bG$GCES5M0$2!Y2 zzlkp=P{gPyhN!NMB<}D%OWTyxT@Os~aF8O~FabyjXLLrzt|$!oj$PP5sNPVV;&pm3 z;3Mf#qC*->PSMRdYG;n4`Ay>)H(AEQev+>A1Muaz~8IhD?gx=pJe=R<dVYX)-q=(;=8a`?nf-JUTuL${~|=UNv(ntD$^u%}ebV(Gn3 fuKvGbaRM1u^dG2L`b@rjDCRZZF~^7Umu~+Td=V}( literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js b/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js index 4442e3e24434fcd4dfdca3509b2c5e3265f17337..ae8abe56d35b6dd9b08c63521fea6adc1a55ff1d 100644 GIT binary patch delta 70 zcmcckO``F;L_-T>3sVbo3rh>@7PdfZ11^1iWrgDW(xT*4-^7A~%)Io_ARpW0jMBVp ZUGub5BRvySi!{rWL{q)2V!hnN0sv`K7n%S7 delta 21 ccmZqtE^+ajL_-T>3sVbo3rh>@7PdfZ0A;`j*#H0l diff --git a/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js.map b/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js.map new file mode 100644 index 0000000000000000000000000000000000000000..34a06172face589e2eba2e2b038d1546f6431c3d GIT binary patch literal 1242154 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

K-SbBNEo;s2K8STi;%Ve%B3 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

|z*}K_z*LG%V%3Dm# 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-8b70.46525646.js b/priv/static/adminfe/static/js/chunk-8b70.46525646.js deleted file mode 100644 index 68b7ea1a34549ac231bdd22c7b555befd3d29f4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3190 zcmb_eZExE)5dJF;(G?;}bM~?#g$$wFk`7(FtpnNt?J^^vrL(1lA~lk->nZy0JL=6! z?O^#Z2Z*Kf@!p^380<2Y=pEm|su1z*8>>|josiw#T`wswN}C4P*Cb9$bvu2rx|oqA ztKObpUWMyY#V*q-0OpvbRn7j`zP>yXlhVS(I+MkYEVjZ-RAd98{_2%1u3PPEV+PIkTp?-Yx=>rOlf8Kqs zFYr0@&-wdb_xLQMN{Jjo^0VG#im+Jcg;t=P4J%@|n`stnMMC3~OoS7Mh-hWNl}1(4 zpZrmqJgl%-rZq=cA*|hLlZ1rS!^?+#fxh~m2$NbQnc9SBb7oV$yUGMw^KS-{%s}kI ztP+Ivju8nE~t}%IqO$z9u(SKr{Ho%k27QT2v+vFeiy$Qk` zLt-A@y$c z7j`!g{1>oRY=8z;-adsH7u*G;87mIPXw&K7xVmP38X;jxX@rMxcmd}%{^q-Xl(I;Y zSKbB|hp@-^=q(+pfbbp{e%!Pc0+X&=9S(R81D>f^mI)x-z9Y0|;~tHz99oaHKQdwq znPEN90&|fLC^FVJl-bB#&z4N#*L=C?px8SOEl0}A1Ik3{(%0I$Q1z0265A;~`0M30 zepnm@7_?_K^omcO8{4P1uajqlQdUG=3u7*5AlazjhjcJtoS@hMLhY4=9C-x;2YzEg zuK7)Tcjvm$C+H-}w%8);u&ME-MEVHZA($csIgu$ah@NXy1UX$J-=MOAb*JPBh_Dlf zTTS7dL4fBv0f_@Vq|FFcNTY|mkl=uX1nG_uDOTvD&^Ge}hEfS@N3by7{fRhT<|G`& znVx@{Pow9vz#41=@~4_~AM(ssCBSM8qu=UM`fN}mbcufmN`H3J_M@xCG;`n!(&bqg zU4(vFG<4htjx>PD-LJ6c_%G`_@cv+r_%$$%eN(U)-Y(jtOEy1_CR0V}Mv+JnL#kzh zTs_Wih>fy#V+?{0=S>=xdsu)2kPS==jmOH5~u`v{N^aZ9{g2Lu%f^_%(THgFu@F0rGGAV1(_vH3Y` zgp9mu1oWjUrHAckb>hv(Z|;W%p^y3TgV3MwOYxyW7<6#>@5AsUwD2}DEp`cEI8Ie8 zGaN_Y-5sOjlK+C*;1O>h_xtyfz~1u}{-5dsR6m?2LAffO^TgI+|GnEwyhH7>1lKv4 z&t_jC(sE&N_e@tBRdY0aJ}YpevyM^vo7!+a=wMplo)Kn`iia_1Qyn$}BCp?*9O1Ra zE?>b~l+xjXI&SI_JD%W11n^G^*HF)m4KpGe`Q-8ZlHnE7&kQ5aFV3IORxf}w?{rac kU3gBn{N`qzNr*@@lzdwPSva1wfkg#JD$vH+x?a-7zk!xo>Hq)$ diff --git a/priv/static/adminfe/static/js/chunk-df62.6c5105a6.js b/priv/static/adminfe/static/js/chunk-df62.6c5105a6.js new file mode 100644 index 0000000000000000000000000000000000000000..c6c4b82ee6e08eace195b19edf86edee496ab5bf GIT binary patch literal 265970 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

I#6sslYO^jwqjxt4wFiGPd7$*u?FWBS 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ᣐ?nG%4#TeHI))i`a-&FiY#WE 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 delta 27 jcmccdUv2S!wT2eP7N!>F7M2#)7Pc1l7LF~Pi}wQnq+klE diff --git a/priv/static/adminfe/static/js/chunk-elementUI.708d6b68.js.map b/priv/static/adminfe/static/js/chunk-elementUI.708d6b68.js.map new file mode 100644 index 0000000000000000000000000000000000000000..b49ada1f78a23cbb7bebab63294afa66ca7af744 GIT binary patch literal 2312798 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

_y)Fo_SIvr>gusi*-OJ``mNTR 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

#O|}TOj8@>7 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

Z+EeL3E{>8@PP+^qg)zv*~kNCf9Q_RIT{W0eR)p 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-libs.14514767.js b/priv/static/adminfe/static/js/chunk-libs.14514767.js new file mode 100644 index 0000000000000000000000000000000000000000..f1452865b1af0334cbc57c53ae0f3691d00b5823 GIT binary patch literal 275816 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-libs.14514767.js.map b/priv/static/adminfe/static/js/chunk-libs.14514767.js.map new file mode 100644 index 0000000000000000000000000000000000000000..b0a81d9bc2e6b252324dc579d4cf07fbd2d32d51 GIT binary patch literal 1641569 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 z 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�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%0DT_rb<>~LH*!L%F~wXqHWe#d^GcLBN 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

G#Xe2X4^rX9`IP4h{WCRA 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

&ENfDG{$1P^uD9dv{j}QK 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Ⓢ~4}4!eEYYu?n|6b=V_jG*pC*KvTB$ zFa=Iu7{Ji*2{{{JV|3LjoOC)kJDne4`$DHn$NujAgC~2uJp(!P6r)24gf`X)zhtT& z(C?{-4&#c8eH`^0aL#r;Y?_zCaTC(E8_*RRI*xnEc=%FbKZsC>_~XH9zJ9H~i5daq zG-UX^iJ*Hdm<cSYoHED+eZ5w)E#u_?x1 z5ewn!oF%bhT(>@%2){*;bJLZ`Vs~t`dRlFV4VU}BCQU_h zAwCl@sSWX@3%0u>0FD!eM^zSM`{O)>;mEC>G3PWco0BkU)}g!bA9gi#Tpq-OI}Bgq z77Xk?J^zH>D(ohctRRLCxK)b4dz)P)!N!59`C=DiM2N9Bnaaw~x8dN#-)6ISaL*sZ zES&F>VYCswKEO`IYQD5ak?y1A|U z1eEiFY){%v#aU5^g7NQpJ5}v}G|}iX7S@d=EagJ>?Q9=m^Le#_U4)a_Jjn*QP!J~K zTV8g6W<2fG>FgL>g9C3?!Us#8S&nxzQ!D77=G9M=lOayAzCW6cw2!E8FSQ33B`)p2 zPKVt`UggWRGotb^2-WoVLfD%vFwqTBPyH^0>|(yarpbuJ1DQV=nT#4?YY?10LQ}6W z_O&`EsK>~s1-^QS?IggN6o#}IuW%X>{u9I;0X&zFZm{^GX2>_@>(o5Son1l2Mqq4_ z*yy`g;sOlwl=l|K8m4N)K%7m@D-I75@0Q&$__2S`Q$wr3ZUv3MzdZ7nc1!b+!_tgz zSX;%=ny>dPkveL0ClOK`#3&w96r!89R6CpWpz*?P2GBvf7`+ABOXYP%5-RtUg()gCdF*X2s#kLbKX= zuPMhFuWfj87_Awu!_-s!#PW%@HK48M??>Fbj7y|ClgBzc0-sl<;kF#y>^suUnWM?s z>GI|B;B2jLK>hoX6WE9x4r2zNx>;>K@+00OPYAjLiB4Y$p6fH}`A^YZybChtZ(M`s zne(RElSPU*ny1Qj;4rvO3z3qnn-0*D7gy0Ze(p z&aI1Y%`4-XBg`*Q_tItEW>}cNmeKJ5Ly`Z)nOh@^t)7m0Ou_MLwopvq-R0^j7qU2A z#1C(qNae~FUF-3fKhTtUh3rhuecNl%`+TJs$Bj3UN0z7NhgqbUgyGC6YxXPz2=e=8 z1z)PGdv_=@$Wj16A(fhh-^WH75tPodg6g2MlvZE>KH~mPW9-44QzbCm(+$dppq_H zl)&3Xd?I0hU~eh!gGuJ9Wh6vfE^uw4)oS~+7V2kltW{I1kVJ9Jq}>( z*DnSH)sFX|=J*r?YsXe0#XPnZ=vveIAva+uH_JG623u8JiqxLgmCA(sJUBk8ns7`= zjbhcNeuiy*2OO)t&1j9y4c#4T!)E@h!@&^byWdXN1bE!X|HBERMR=bFpL{|NcNNz{eVuhj;S{HK5Z_ed|sDPtb;#e9_7%bKhCzqUX@tx#B%3^5GB3VN^MVl*n1B^M2;^&kd9YI*(&0Gp zuxewwyn(-c3+dRbU4W&;2#rVhAdE`F0nVY@xbV6T;pU4=i~zMRhP*gXIWtt)YnX#v z(E-V#`1PAtutJ#}0fu%klT%vM_606X80hP4AaH~0Rxzj}L#kWF zn!8iY(nf`E{0Tdo%0t&vlFoFp)f|r45Dn?vX zAooSMNJjhEgM0m7XP~pu{3VZAjZR5*Y23>>1NSA6PcJ4DW5A)bMD}Rjry}14Jjo1_ z$L|APn!@$wplxB8bmVwt>qIJ!R9cBWPjwXvaSQHaFUy(Zw zj^-!WVm=&UV+;!zF4(y8TOVMUcm&CzYG#O}GyykyHF|aQ{^Srm zfLM02=uG5`Njjda!LF91d)Er7N8j1b_D+^Z?_Vvk9>b^VGjZZ*je~>-hoklT<9*N+ zXHb9C!l|ept2dDG?5)WkF170ARPj@pbV*xJo*R>Ft{vxV7ee+5HUYexPyeJ}knfP8 zm8po;5E{H6auTtda0FR%rmCW5YB29*hoZ9R;OhejHtctRVNbAtlnabf@~6MD45k@d zCD^n*MV^A$da;8Xgo1>zFOEAz#Vxau3e%P!_@YJD|gNPgr# zPE3U+pj*Wkf?h}CAK>r!botliTPzWvQ#=goBCvY!@C+^e0=q)X&u-7#%IC}zxigwR zQ}|<)_r`Ws9Mc+()V9xDMo{kTV(OZ+pP&*~%P_SMUQ={1j~`cz*C*G%{QZ|VzWD0f zudm)u2 zXg;@XU{rzgTGqy;AiTcW|MjurL(%u?^0C$$!_U2Sx6w>IK7k~;N4@fde%m4_cO+uq z7e#OyRN#8eW6Mw=lNF@U462<%=xB7dItu4@=H;>o`>TWhJmb~#Oj2r0n z!B?U}(y$`_E*A*j$;Z2M+wMcdmeMrF4|5R9t=W-Hb)84mCC?TP*n#C0F(Z&i71aj7 zeAtHidyCc?DoKtN+cr_#@EW3g$Zizoa3?QXPtfe>xJG1CF=`n$ol)70tu_qIGC2vH zu9VS`z`BxA%r?s{RWKI*SR9J>HM#$wjT2=DKZ9e#E(lOL&=FC@MfikoTO3CZliG~O(d`bf8wnp6%@3heY&VMP5Q0WUi za%wasTmXowkiS@X86@2@6_9R-Gj5y5yy&oaUya$HxHii!H%46d2J-JL&8p(w5;9rf zbkQ;Q|GZIRUpuw6s>CocNp2LGe;Z}!)&|nyv(1b3zZPMRd< zr#jV@1!Pa+SJQ@924ra;2;`W@#$a#F5Yo}T#obJLMyg2v0tT@A!*q5L!g{-{3}&s;(?9mraz;INRCh2m4i30b)?TL5b^%SPVR!uTB|( zdFR1T*rS0fgPLk`^lFI|Cx^#e{KGemyakmsK5 zn5d;yt7uNR$N1eOC%+jl@tX^%9g<_^3}U$cQ}T4*){`%z87OU$A^Z9UD?Jz3`DHMe zD59QgyM29&6kR0439e~y)hTY>uYT9%Oms~o&TXsTp6vURx-3D@b+B!mVKVhk+k6#h z^Ys(R_#vUVwSK=ic!&h_vqNYAx@zh+Cu2pM+yyq5Siss~nn!hMI*YKX8SXc=#xo`I zPFU=V+ywa38lue@nkk@^FpO&ZC*r13o>OU2sGHoLi;*dgNyfK88-_RTQw26LZRO$I zR#$f4$(WUz7Jh76DA>Qa1y?r?28e;*e&jYKCIPCZ%$SN806lMh+`yI5`d?=6pDZ67 zP47+L`7Sq>9@sR6X|cdFW$wnOi&0`^u0sMjJUX#qxlr@^4IxBQ)Yl~;f4~_AcJLpA zYuDx}kWJ}A3?5;dW`UhLGJ{$%^`YWEGiC>}C9E7To64YH|&&xgg^_S8v(MhoEU(==Oz1~V1EvpFY zq4j-$f!-9kx3D0FQIkFSEEO^A7@}aKmqdkIUu=kJobeA=2Z#}E5_WMt&=MWnTt7O# zz3)W4cZ9_LnSwUq$OY*Q_l>i3S~&yjXe5wGpth`fDlZ?rOyP^f?vds5i3>fIa>jbV?H~|`2%3Mh%YE0u zb$p>=YvZ9THSV-NYKn^9tsO1U+?~PM3k->fx|7)5E70u7KxY2Arw>=*^`O}$BRo|S zwhH*Z(mhwqvPNFrqG7INd8}%6N@i>cK&HOp4X&)}Y%RH7f^3tXhSpFLnlYDyNz+{k z4ZM(H(TXsv#~z!z+Q0@|h|Z%7<9e)=C@~9_mj0FHYYiNu?Ciq0kFfMoGZkgL_z6ZA zi29ykHZGXhU^)~D^Tp=MX++ESnJqQp2S?UGdtoF){7#m7c+?ra=3unG2e{M+aEu3BS~4&KQU1u^#Y3Jnruhyl z3*79B8#1QQ&D^lfIj(@iCdU$2F!0nlS1BPWP~5F+b!>=3KJ1*IXPOymEOly@wu)5@ zZ~fRjfg`XX4rt-@M6D|}@BhJFPIjiaS!HVniEQw3<{0FANntB!ptT!#kiUW1jdp72*+OUYhmUr= zHJr3vpJF-d)O2(3JvV`fA;jNd_Y!B9?czj_#b90ghvk;}mwZX+(+%0Z@~ae;wy>mx z!=lzxykUhlxE7S{t?AhB8WB2FY(TfJe6SN^3)mnyF=oLdV~ZaMC_oWnF8A%!jRtkI zXd*KSDJoJJ1T8J9^VqxqP?qD^=-HJJwl=IoMAHyWDcGq5dTVg=DZF`3YVuRcmu!s@ z(t!ND4Q`I)Llg|(ue3PCOj3h$Kp)4|C@J(#^6Zk#T$dr=R;G_X(+t5?`!;oD*6U9)2i?U&QI&^ zL9jvMw$lqnJbaJyR5BZ`UM~}xG!A_@c_{^m*f8^>ft1khfIWi$blriQGO%foj$M0s zIg(&yG=xf)n|FtXj&};l4!1P$q-MmWPVsAW?XN z3@RL;1v`$b+Ay?q#p(eZp0ZQmN&FQmB8+-U}AK5OyAq|k zeqz4BQnFfB*tpONV=19&A-q=eSFcc}IvNc@%UV>6kYc8?ra}t@Ev!gZvpX)bxydWU z;bIwfiVA#}8S6Pio(r^t zYc(eL!!(buxsmW-i6UijCXGm_sky-(njgnm9N3E2o5#qKZQNssQzK*^S1X=7OSy;3%3-#HSV1?0T8 zuI^d?%6a8Y23xb1 z#kRnQ-bOK5NqK!`&$G8w3e^O51#4-piUg?#Tw1B;uZt-+Qe(LvwnHrUdsja(Dq^YK z-i~TDzF6u~3y}uLa)#VFWAYc!7B+C!=7GivZDU~0O<^eqNBNkxa+3`mwnw%Mj_Mn5 zsBbN~sEjQj19^eG3sl+w%IC`{>EQ}Dk}`9S;TK*|EN!as1~t`FnK~Zfam^As7cCy} zYXz;z07FyWoonP(=0=fn=(yI7sdTw%O(h@S%O%2xkOe9cLiZwB>4cXaV#-X1)|dPn zAa>Ww=jhSIAH8XI!cGb7IRE(ay@aJra!mu32rzkSMV_HfBTofrgHOoN9JvfNu21C8 zdo+W?lyNe1BG-i%=-&5E>!~iHW$rE!zQsz)z^EmouW16J znX4Ja)wLjn_giK&y1TO`_`>MmP!Uxp)XH?cB(((KVotuYQa@RgahU4@{s4gE>V7E~0@kfjG%^s2u>U zk(tDZv+B?y;~+eud~k?B7up|MeY@%3&XY_ZL}pkKVj=|2yo%0qL~VKd5=r!g$ojnw znwzU)6P?yaHANw4FGgt1OlfxDFy>P>p)BRlRHxO#)|Cj{ofzZlv!}L*L2lUXW^7Bgrxx6+pE-y0$7y_@mDmrI}+KM zqXkQ4kbA^JK5FpQZx!IsmaMw2;~Z$Xb9G+f)`e7bfxw5Dn`H7{^0e*hr<)WiKzb-M z>FQ&tkP;G?6}fDzh%m)V!P&uKjiXvf9vm`sqJ2wO5JNq0A=pNEd8D5tIhb(;50rA7 zh-*uPT&H@XQ6)Po-K%}FN5+PVAHNyl>m~06FyY*Q?Z!3yin^r zz0Sa6_~w}1zmvRZ^P zI>y-p(^W^ul-8pn8m&iY)Z(rW1fz<*s&y*eRt<%e=_+PnkLjE{^`?b9;VgGu+&VPJ zK{E|Dbvundvyg(#XGom?fAL{rKKg^`A9p+q-Q`$Vh zA@!Ufavmx^b~P?NVng5?gnw;$gF1T(5kw7j9IUyUtXVfLIUPljI@ssji=d^pK(<~N z1TfhpzTZCV?=oPH7FD$E(pqW@*fUr%b(eqxtMw;K894LlyL*cVOe*w-TIb2~Cm>U9 z4pkFVc$qY7O z&OYS|D%S6Env#M;16U+-G^NRH*|vF=w0P}WJlEV)X&7N}lS~12oXqLqX!bJYzH_lj zlI%CAc%#>Nk$vv&<`9G0AR)@ObH=3ec#lReki^^NXWNg0lT_^7O8tUCvs0P}CSs~6 zyBZ*J5FNzXgtB~h36=~ZPbA?0Tn;a8*!9rDqJ*LRN5SCw3H+5 zoi2^DDk>B{+ug;dwffOB8;x<4g$#}Qu-9>z}coX2OpAvZ0BA&QzLfF zwWDkbCDNJ%-n~k7D37EV;K=0s_sA-m!p!^zbVuz%=fYqgx@%_dVtY$77hyYuSdD>? z!*_IS*lw7zYtC0_zXTPRiA=!}*|d7_K&KZ-9JEyM5y;UG zj8jY*HWOva+;uP7F+($iiKdX}5ONEZ#sA1gqwi-MWq%3j!?HNTh+s(cDCN$B*aaVg z=R6ooLp34-+90j_ILzex!KFg&-sp7NXS=nAUIEdl!QC8a$4$V%XiaWi3Vp9WM0fe8$Z6k;wn|M3PGtj=)zf{MwKxuq;yBs@07E zygDhTVsa$F!7u0X*t4O3g2BFGa5Jf_2mH07T=XM@9%3+=YlCOMLF?r0>NO`TXFVO5 zwcfH`M6w-D(KBnSj~0WGDuV@m2b*C`2}xy{nmzrLJhrZ(5YcXzd=>WGR8Ft#rfFRc zfn~?E>et8|4GEa1qd13JSMz1j8$fvrLM;;l+mC&I!m zr`Lz_IiVvY5+)Ae=9NLc(aFQ-pX8E)T_OY@iR2EjSC1q$2nD_-IIiI~iJh^X7vOmr zOPh~?H9t(R=>75YPa=maf#E-c-hJ}5_=Vp7;D2M&KX;# z3#b>;Lp$2mosvRRd(P}u7b#oBZz(=i-W3E{**$!@zic2~mg4CW3-&e7rH&fkvnroVagx6YWrUP8CufZj`awlF&GcoJIMdY)fKm zUt|?s-PYLMYu~(ifSq7V$yV`Uk)9qE8C#zwd7e_FY(`h4Eb8S_X(=zl@AS|nlkkVX zD zi*LzQ9Ngy#H%*rM+Kwa30d8;T01xPLBq73UtxPLmJBq9^>46^1M0?J>HVtOC85MP- zg33e*gO$kb+cPsP^WZ<;!X0A3gxi~kk8^2uaIv$y+AgikH(N;d_5QK`PTB^WhFNC| zFU4Fv1u;(M!9!-1x~ZyR|KsEFFHLJ>v- zWQD{DU8rQZ^D{M))F2W&Ykz=MdV) zw7wYT=0U4N)x(>LV69p`71Ta{=x4e35lKX$y>S&4f`rV@hY7)5U*)~=7=J%4v#`?u z=J?V~#C}Y+S4Xew%22e%NcA}3Z$<%n#2zj!3gmod?m|o_wwa7`#R zCfjYxcUdW1W59Ybu*semo9(_hq$yu9ji!&`6_7oI5oCa^iUQons#Xr@inVti&HcpI zI@71AsswW^B#cL`>!LOaD5n2^t5_$uxN+o!L`?AZllFvQ(buiQut`Xv942!;6T+p4 zqzLbEITdKD52tCaRKUf|Nq|L>$etDgY>oQ#m>HOTG#`Y;DjPGq9ebUSrZU8!?Tzu+ z0V-E4xV=wTwYgZso;R*!cnv9|wbIG*l5=7%&4RiD!XHBn-lhkO#IZ)Y=%Oe% z5)-{D07)9757;ik!{(A!GvXOmc+wF`-yUKCw`TH799UsW>jGnK=Y@$-aUmbg$I-&Z zi)^qvCT~`D4lz&)wqxh`FFH8RGW^GRyA)?ui$<%-zszHWh-f&^;8F1W$?1gWJ!Lgc ztlE{-fTmHqB|7tHl{$5RKeC)lL@Q!{9g?wf9PB()hzy*BmW}Ab@{nDK_AWE3ni)U6 zy&osyoR8?SnxT!p-O4PDI`7H6Xpzzs?ITSQC$7K1@njefpiT-G8WTb9vQw&b2JE#~ zOcJjBSj}SOGt)Wam-E&7RJ_$0Rx!~!M;JC-&7a+9+?9a_34KAW?w|;rUOaOXpOynF zI_%KL%c;kEsVT4$qb?R*fMK7_>9Kg#Oa>noXx&dv7{}FCcn3$F2Fwpt8gVC-t>|E- z6(1CW%bAlhi>}T3oOkAxRw*u&0Ug5_HQVvc+|pUbz*Vu*6dXpuJmjTe2H4NedJy^l ziLJ!M~RkBSpj{ zLFSjD%)2&{i4ERRdQV}?5C~oFNf|&-BVyImM5~}gYdn8nFB~?via4C6s~(|mtJvF$ zn&m3_l9@@^^agw9_#3ne*a{4{$&rARw-N5tS9`Hlu%Aco;VLEG+`ySe{#RsC#kxvM zDODW!mC5$p)?2a2DsuxByP7~J;l>lHIgNARRh0RYJC{XMLJ$O0Xd2@ygwQ*1!5r<4q`o(|? zrGl(0Jz43(@{4s{ZIYC3nww?Rwob-I%0sTh7L@7$mnjh2?1veD;$ONN+6Scu_~!|X zChNlh$m}xM;r>0gx0Re1lqB>!wu7r9iK5&}B?q{BltyI*(i`$?*spxGwS`%xCj3-< z3l8oc+sN0IN7CT4sc?`@RLs}+%ugj(cSl^%wg|VDodeCDXLlYM8U zEo^_wmTZBzJ8WO6)B|sT6qrg~qu6Aex0IJLcKQlStDqe0wp$152>+R#?)zr&f@$*} z&M}(4pci)yFdE*fKqBo}DO=@G}?pd`pwSb>&%Rvtfo z^y1c&Cy#2DqCQZZl8D<+DfCpSggGk|H$u-kM^b^M_|KT*3D!cxth5OLOWEtPyPFbY zlm9jwKu3}Sa8v_nknqbI8!AMZR# z-{~&zlmwlb(J=_4m>xrVPGb8v&9jZHbZT!4?Rnq{h|>j-!cUOEkv33->-V=v-vOLu ztJk>wQAWb-9j=JPa+;YI$sf9-aQA426HLJ&yopf5>2LD;lOM1-vl{pXemHHw8ytTa z54h%LlewTacZ+cfU-Y*}^T$2VH5SLZ5|3z!f8BX+sI~b)xsCMpSf+5#y@OQ&UtoMG z-+RNOsO~ZyYaCMm6r>ssc6gcE3VyMg%7XH^hK+RdxK=$L*N~?M`2r>7i?Ad+%A~;cfha9nX+jI)eoh z-_3Xf^VKpvP+vx}F$=aA?RiQEb^bKA7bv0Wl_w5MYbLA9Nk{{%D{N^n#94Mwh*^kM zw9yhQCq1t;7&IzmU{#5+n&Rgj=O_Ad(MI3oh3AROpja0!kaF^vAqW9~%~CAZ@P9eI zPbSHs;(G(Q>9`zekKiw$cYIC&%DAK6A8gWQ5Geb{5m@1k1RC2$voRitici1&=EhfD z{D6v0fd&t8E3#Y+TY`z;?ODBoK?AMf(oH2B$wz?6uH#o@TT;$JZaf6$4I)g-7r)A7qiqy*QCUiTt#XGmdjO!b$)R3|n0*8X)U zbz`bG?Om%^CvgjWUXlyy8R+5n3Zkxdf`^DVGD#{^4i(H5k&{xeD{q?Ujx2>cS3-p$ z;Q|6ZzNkl0S!=eF7G?X+xu3UwERg2#{7a7UV+_xB6&DaUJ_U#uc8ccJ16-H`USex^ z%h=g$aZ=}gFBANClGCJ1?BPv!+H_v}q*T{roh|6`DaE>}CAxitiJiuZ4TzwFBddFC zx)safB^HS0eIqsGOwlVet_BQGis_opi)8H=)=jn$ZA&@?KGP}WrAvoV+(5Bq@oig_ z7jsE#tQ@aewvu<8#9bk7DTl!Uy^MQbVBI%4n*VcF(2WGy+Xk;VCR?IuB^mj8**7e% zbKC4inh!QJ;%L6i`~%9@e}mn7Px2F>`n@6SE8abfxS@DWl4SvSR0S&_8nLu6B>m^U zR);nx%`k#y95o76S1nxRHfPo!uTj4som{aB*^tCJtxwc4ZG(GfK+eIz%&qumNNr#l zC6LjZFX6}*dJ2AnCryW-cXE-z=#OZ zt{vw9LwHE~I0qFRoEsi0HGWoc^aithqz=GR|0g}~BL#sWD&_z%M z3Cu+hOU(Lt2#Yy(>NVA75+uhlF#Ab&8ju=8gn9>PzKk-cr%N=YL|O*wx(AtM9y<7x zRkR63#sdP7kH&Dfv+jY9UL432N7)Z zmvij4fWZ9%Rx`tgbbYdsO6~UQ7~75@SI9(o18c*F%T6%7tt~sESTzv@0k-W9M7L_t zqI0@w2;@~k3q>zf%Q?2(%b<7xsQ4OGQnA++JmLjfhLQwIbG8jE3F}e`?Y4;Z=7oOx z1lP}yZSB#7I#zc}q07&Ck`td^lt55P@XkgZTe*c0v(q8(+_Wnousw=9$72lyN?;9M z64AMD^c=WrWQrn^I~(W_ln3xkB6}6~wVJ#o>;rB_v4lGR9H-Kre}dy?_#8SdK}oMw zAd$*CAO7|E_*bM99PW&Fbm@HyLD4Ph9$P#RY#WLdZu_M5Vq(2q7%DqjR`-k9Op~Es z28nXB@qJM^FFkC^4gz6d=k^*i3lWR$Z3J3Y1cNw)>CtSDcLNSFEoL*hsWk%2e1gVJ zI|FA#Sc^q_$Z-p)!T`?k1yhTd@JDzfoAG*13q~coJtKqQ@TV9uI|ADf1NGg$Iq9ao z>8D4yYmqAg+egK2Kz?jLM&l=79-J@=x4sLOE+3XvpclW4ZzH4P7~fbBCJ&sTbKTgE z=CG})4fVvH5n3|2={?)R3(#!Eu3%daCabpi>X+LZ$jCYy5oC!eEimkns9(h(>Fk)@a$l}sggx*73X%YGV<(UC&v0wNRX*%R}qbk*?y;{N9+u#x) z338kZ157WMCLFz|42Z|^%K zVnm8@`B1s9%$R5hN}NQK2`dkgF3^0&SiL{2Ce!)y7g7^2{^_^)cN2|V-=nh^qr|=# zar_D`ASOj7vE6pHg!9JlqKfV&*t5_LU+2XEakw~Rc5ja)F<-MEk*F|cR<=+PsIo^% zrwvYa1P}y#RXL~0-9x?(isrJRnr&2Fb5bb7wC{ZVckGV5-i$;68+3Q?aP`kS7RIIO z1850Ve29opt1P0f)+Fp7;R$;S1gkSjPlR!)epIM5$EkBGCPZG!Eyosv+;#6KBrT`V zkw6e;M;XE(mmDK2b`ed1tDQg6{tz zHy6+p6F%HUY|tTu$_Zr{Y70Of6nXv$w@0DnbZ?xe1RH!mJKo2jd4-hWh1MK~1R+9- zrdHVLK*i`<4%0(Ytjyj|KknVBHs$^}*kO0olbdWX$qDtHXf#K}Q4o!n0g>gx+E9NU z4fnPOMUM!k(^Ajotm@0T7{kGNAM2%u5r6BKJeYge;UIzQqe*q+yXKdw+j&>(Sn= zIyxOQYW!1;Q2b>~s9UJ@8wU?yRLo~5ey*jGIJAmkP$~@E zLqbC^y$u{$PU9YD;jh5K42KMc@MBHyF$9-Ij-7VU}EjOrHZR1t}t*^hRG~&MLY8GSh7+2 z7ja4!!kZ&}bnE_~_Fg=B@Rz;&80XH57pom$fp2dAdGGdLethuv7mse;x%Z$ha=;?> zq8y#4qYW2Z!*c?rHR!$XJaTKPRksWSFrleAFMGn}56cyl3Z@>X&J-zBP~xl2&|N~- zWVOPvYQJqt?XdjYLmqiLf#(MM+c;s%l&xBZ;avbqdy@I3xk5ldDt>WuUw8Vd9WH8j zA^#=_am001a+API*XL!FM5jL@yfv8Yt-6t9>|3*oXVpCXQg{d0fGBU4hB!3x3oLF} z!0WRU;%Ghi2ku$H<9`^+Nvb9gYz7#1f<|CvTCp8OFT0Ksy(27V@k~YO(|h&{H^j)Q zcv=GmmqQlAGVxiS%EnxSB>A>3uBN4DFa})@&5NOzNR&BW0K*Kp<62(S36tjC0MSBU zV)+WA2FIrTY|LWD7|_Wok6!EQ#xKX;j0b4&QL$&-p`e;nV_(!5F%w46@J` zatL2Q=#TD*_o2S|j3Aq(s#qgT3%3og5RM5xREH3_ zx|4byw3ubIkA*i}Mj@feAS_NfFW-JR zbl4yBU3~UsjIHV~$2W>$MSCJg{1FZ@yidRT`fIpW?!uscxqQd#F24B+EV*Fp7>>c? za4Q^bdygLtzWMTVKun`Mf<(pWV~XC#r-%bJxfS=-$W&C2W8Q{GqaA^s2dm}jWR0jI zbb?Fg-g4n;TndLy7@1IzOEtKjywugoo)-WThX{l?`Y9T^3&tUT|GWk-=;;$QFB2Q0 zq>Cn>;Do@Oovm}yMN*4Y5o1s1glwl>bV44^7m>w2P_jAIv@@IC1P zX5R6MEy*T@Q;=aH+bKAHR6JVk9ZO zuSsgnT8jV@zxEGUf$ZNu+uvvSGuR;R`@zMGHe`(|3r7M9U3QBj17H^%F;kdp%Y_6ImdvFj4;WGOYB7q$S%$AC z_U!-spHdLRvDrhfnlI1b5{NSFvx8CxjfYGb{2-sTtd5)rcxX#ubN~_d?U&Gg^CNR2 zKX^R&4j6oOvv25M1OPBemaF#)On~@0t%A|&{^Rskx5KZ0ZyjRtI^zTKCI~`iy!do^ zAYsm_fD`)c=ybjd0atZJ^w50>Bwt^=9sdg2Jwa?eBpIT@)o_K2w{yg{!}>j=phJV$ z?|g}LCN=8N9(WIe8wDWH`SzgdE~ag)Jb-rsJnEK!H3phILP~SZmNX3@kKPYSdhl_l z#)_&^F|pFu4xOoq7 zE+iZ;TekrzWMZ}7cm&2Y)1e{br8yb2+{c@wf@ZO8mNisB_$0h|XEzP~JYbn_e^s$S zSGE-1ja*6zfom=%Bw}sEIb1x~HsAw%NPov^!q2{h38dhU#t!Uk=~|l=5NEK)k?C|c z4H}`e7awj}0oSybJk4Mo$R5RN~Rp;Ox$KbW_bb%hT2)PAhurDG7P@e|5K2y>9Hbo(BuOD`mq~ z1&wGVK{odC9&%KP&zk8}bz?6N zI7?qF8H%J2N?t7UQx+qH#QF?7Ba366FZ6*((3z2|AE0N5aLLyWjNQjzZrH+goj?toRXp@gdzfpAZ)kVW@Wo1pS{i;Aj_5v+Ws@tU_^~fPbLUBUu2(~+ z!i7Y@5(%CSi*;ucns69sas|XFxZ_*$GkDyT?6R^^%CanHitaWs!`=I;9xfj;x@J)y zHa-mKW`?xW;Cp(w)w6>=8K z#jZI=tqM+Hx!n^k)45swF(_|OR=e|ot)bp5anULrfVL@w>0X245!{IRe0@E<*)K*cb0lfk6 z2Y;XN#}r`Ne5bL86HISEe)=a(rf(iK+MJV|oKts>X}Pxtqi?oe?BGzNnOQ{|$dE?E zvFvn)hCx=TE3j1a6YLsRq#se*Ge5}?VQ+7gJCCDo8!6zSx#ypJj~0JWXcZ8vAgb@L z+oME{X66k8oa^5EQvLW@G9m$M4^IS?(wUI(RhKEMqS%ZpP4LN0N#a($*T-qQL%|c z6h(zb2Z&|1(PKs%26M9se8+!sby@ZR`1wzv_>b4u-_G{0!_{(h9gAf6+POGHK7f-` zNfp+qjKvM9!>xIU9kq!HjuT(V4V9P9CkjhN*#Ay_WQb-L`oY5|_a5A*F17*B*GPPM zZ*iA%eM_f=PTzOCDrN5=pVNDuB0-d+MdxkmYU=V zOd?F34T^I_Rgh!eIpKx?)(mploRH0#^a+7HD)dFnSZjj9S{4)VO-cfwjQzfNlVqV= z-RBENQo_fFQ>C#nm79BJv)NuzHdIs^1!z9@iLV4f5XsU#!2@)L{JkUy!K6W==|hNV*4F-|n)I;eNg74llvYX53euh1574w=#% z8ie#mxE%BBJ^_PZ3J&B}8z$Ec57ukGaHg4sF(Sh9>{e4_EmbE7 zRrE(hOG2(F2N$9(Fxdts6`^7;90J${h#1%fhPb;3mcv%$5|DZ{bGuKjy&TdpTA@Zq z<;ju!(G%<^&JaInG0?Dbm%u-Eu4C86@SwIW$AzOy4kH6dU>lSCG1l7M*EF9w6f5T0 zqMc&^Q(}w8{d$hDOf1p36V5?vt6SX09VZOZ&NysEwqtNGoRfb{Zxsb|hCTrmxX_GuSHS3-$|y%)E+Q z+D2A#Mb{f5N3D|u#9Y2~r&U_$!_5#zgou_$_1p+UQBMVqZ&V zWRU7LF(65O0nR#AD(EjjRbVJJyGiv;RSM#LQ8zgQMln*C=_D8=l_UG2u$ce?_j0UHhpb&N$Jj42B_qJt8P`54qM&Ib zjcVnYKt9^D)(AzJ^S;Io-=7@L7FbSN&uSM-X+W=0DT5nerKBFaKf}eoDFfRMka0OVLu@Pd$L8;5h;HDzFE|p~)`9-ut&PNN6Em-duDt<;= z79ZH2fa2t8!nfeft7S1vDvpH-WTqCTIAXSZwLnsUfJ%;FQ5evIBo{cvi!T^mIVOqp zB6zxa);1{NS&LrUHmG0DQ5G=)(;T4q#Bf1tq}1PlPfBo(*`0(G`(D$fj!M$Y|7_=P z!XqMrcYa#_lOM;(NQ&CVIXZhOsfR}mF`)8>ol3jTsk2l>!Rp6Fz9<`$pl5691u3O~ zbLMqBF%FUZ;ai&NJ1^%)uzBVAR2eSPN{@wILQ|t6=TE5Nkg${Igv}lp|Fl9@uP;7F zj?SMMAaEO-^;ke$lj%HOBVuGWykUT}^N&f!Y*z>_R8ZxT5f+V+s-l>1^x&ZQiZh0RTX9_~YgHI|yG_5>|NYvyY5ce5_<4QaVqT$B{ zUK=6@TSL+o1^{7=3Lz?8_}K6aN^d}hrv@i=(GdHEFapvV%U`=VVJNtXn0L9zUiZZS zgJ~e*u^gqNBD+R6|@g!*~7Q;MWmPDsk>`CTygh9mP}2-?_)WIMbN+Knq7?bQ2ry;I>14u)thjOxfB zL06PT%9UFc$l6B5v+v6B(WTw5%k50WO3e@jbAVI~$7i_V2$5bUlz~C6{0z{(VF)Nd z#e|W*rGrP^p<#%okTf9}#Rs<7M!^f{9(RnM_xoaC3BzhTLGH&i6|d1gq|e4yXt$== zSykk{qIkJrfvnp{QcQTUNzdG!G1^oyhD2~-PVc2}=U`Q@!%tUL)&mF?c6o0PqiEJ< z2%b>TKAn2-8smh3jr1ZT^a{@)fHkk^FamV-(b~NyU4=-z37eSD&8TD99CkE^Bmtu% zN0o#iT0#4HAau|@5Q>?>dvht(DDLwp;hM@1;XAIoV~i4RoP`55X<^eMO5m(?IZ$CN z(Nu6H0ouX7mSqheJAe!W$#_sqr8!{;lI*k z@~%z54TgkF*c{dYC-E+aT-eFHvxYHkyA3_@fpOae2J+v(`@ZWS>FK9^$RxA7-@CbH za6dYfN~Kb%R4SF!;Q#WWQR5P<7!^9)XnGSb1QxFCgaH!MSoK+^Y^ zfRAgQ_BO+Ab9$W2kK(umj$Kg2@e<{9+RY6pN@0tExltnz>7a#(1&#kb*B7A*B8Y{Z z^9(H@8LK6tp~b~Xn5MXh=$B>ym>c-q@y0P8^EDrZMYyAVn2|t<=anWUEEO(XFCtpq z;%H#Z)@at-Vr%5EG-fzsA*(Wk-9a0oHu?wpUs<8J!M=yngzSlTL=k7WUM#>Lpffmi zeea}?kMBQZjlm*fbSE)-`ZC9EIu9YKSP*-XeC+p3K``gc29#QobBp8ljw1jXz_IH1 z9tGH4-%~NT&XSVLgYNp=IGR&#>Ex(WbVaJ@yyB*)mMRulcm@Y0cS`l)pmGfkN|}d) z6;B+T5&a~D1cjDX*Z{IsC5t9v&`OC9~z>(+#<94yK3jl$J8cW(r^`w*5_&GOLGnMY$~p<3?bWhy=7u zm?=@i%2E!B?A(yb`Kw1)LeZir{S0mB=x2EG7L)-|^E#bba}S(_&8pQ_p^+o2a2!(} zmU7WYv*v6h#o1Nze<@k_)mkg1k!Ka8cd+M)SWT9Tb)u;;zYkfg?ZQgUM(jbBo9#fB zt?@UN39&Tnw1}HY>x`7~xVy(>Z8%>-J-6r9&6N-~Bsd1(U&<|n5y25QY%FBc;}JuN z@M+)GcH`f!-pX5_NnLEJb!efvREq? zSLn|Oz(s`_Oi&qvSVxFefxFPD>QFZsOv&!yEzu#W=DG-tyfBZ%V0W9+&TAFX6+5is zvzNBH{&0uUlf%28wk&CRN&a?-sf9rKZq@F>_)+u~?hbKN6suh9uu`$rltD+^zM2+x zPIrl1ZwCrRrM&kSvi)5&PZfgq2!(fzT#FY?K?N(!0C@3|U9er$9|e#Z?`|M=lM;5e z^L~W5S%LAe=_xSQ4)>1Ko&}$=x<)Mxryd^ya(hEA^FmkY#;TYb%CfJ_eFc$z58k=- zZ(x3Ys|4wGh0s7JWa9!T?nrIJ=!(9YHP03docpVFNW^MU`l?U7-JO*fiOg7cd+B(b z;3=A`S(M|2(X?UEeTTT;P;PdD;K4{lSO7WS4C|vqb?FlmxJm9E5RY+u|!Q={+u9UtPTZ{zLhpRN`ueH%-Pg%xRl!HX(BmPd0qzLhXAn z(cr448T!E3Hb}6*{`)$8Ea_e8ESIaS3^_$~gx-S3u480NCLC#a1MmxY7}JsnUzLqEMX=fF|i_qgVyEuud@EWo&U0 zje=t?!82XXoJ;gL>tst64Kp(VUZ}rWt+%_G8@(+FL34IChqzz56`_%n5{O&sc}ii; zw3_opisi)Sv@F9A9r?1^Seq2AWS}GtMZ!r+;TafNrpCLJ%3+98E7BpvN!i-XbRo6> zrUyydGdqxV6SsnY7eW@P(a%B`!2X?esI>5KbnA5h+-iR`M@P)zZK_$03B9g5E=F%`%YJLxuf&LMAAXA-hcl2!It~xEXCOIEzHU&I6 z35M&Zp@VoEbnT|B1m*?8}HE6vNsy2##(-S0s+$^;eZ5u#1qt*_0Fa^dHls&t2H90+if8H3u4+nRahc}0}m+#yjF5iSrkW?MPr+aVz z2&)^;Efw|#=XT}_j&+qsqP&j1e}pJE<0U+JO6>;C|xW1%IV>pvhoYKX~a6E(`IB^tEhAkl0 zIN1qKxC+CQ;d6??Wq?MyMvq^PUQdpW(UT}A8bU2_B0GuQ(HX}f@+5%Q2qI^ufppyh&LIqvcs`S}AIeLLxZTHPZ##^L9G;`=pMg*-HN=T1vF{+ct z7&^3T7hHktG?aT88Ita8mt&(Uafs_0JGd-{{#VZS+oZ3Dw6Y0z18jL;9;Rvy=@M<1HML4ihk`L|Sv_78iqm9h2K;al$o+mSq z>9x)9?W{hiww6W(}y&zfOtIdH!l~w{(Ho$Q1Ff6Yuu!d2~n?4BfnD+ zKmC{d>B@Oiujm7_9iPZ3g{~z!2}3z-jY_A1t&$M>h4Wu2IV3g$^FgkZW0n^1OooH6 z(zB5hJJ#vN*@asRyh(JxMGCSk$D@*9d@rT~AJCu=LHQXw*)c#>l{EEMX^F8YH4i9P z7ivGw4Dy5Yr@a@F@UR&RNH(LdY@i6wd974ZjI32EB*c=GU~Pm$%FPAc5r$lY#TrpD zn`o2KOwb;>7gVST;zEO^?z<+=`4$()YzQV(zwHqM)FG2WBWb8ctUOKak+-dkTs*PAoo<{;15mEj`)#Fr25@nGtR4w2Z_aEw+WT+oB@;fs@(i)xe^ z(S5eHvyBQ=?v#s1QsMrHm8aTNWY%1m&pXn(SMwxBLsQmZK6RyPDfBH=nq-*Oe> zYjwK9!BS_B_^d-v0csX;5W$a?m~zqB@(_t=oIWch8e;;NktQLTIGI%|9;Mz4=ep{u z5i84qR;IaxF9&H|6P(GaaH&3yo5xxPyUzVSPh{sXk#@G7LuI;l4o@u030AxeDqwaF zFY-ItIWA(G7#zc8l-+e=pLYsTEFd$sonDRqvc?XBS{pk`ii9%9OG&OzgQ()cI;|~O zY4lCuDm^QhuzSE~+@oxjl*QCo6wpUzX$5Wol$0!_D!FTK0A*?xmdUn(SW-%%qQZ(C zp@gCUM^{{K@4@`m%AWc{QB<`f)mkWr+(RFKjcP661kC?_1J&Bu*QIHLVUfZ8nsrkc znzc}yt68VEt77MCyZgSicO`?0a?x*6X{pwi{sNT>1B$19m-2khqJ7pPst)*MD=W@? z^;+etxfOMOCmq}9OMwv$WoHK_C~`(|<*?$Rb*D0eIvw4ba#6F3oL8nWVU(}BzHuoP zY-@uXoE(5g!7kG`$Fn3Y;@pY{9uFvk41*T6I=@{wQfsb@R8h*I`O*5OwqWlOnsQ;l z=>wtz?BjmaE~7=^e%MY>$a+P#nWHlmsh@P$J^=y6tqJY{e1}kgb@v!j0&12|$_(Tc z)iW2kx`F{I!bw zw{k+Nwcxg1&Qhz_&Xxk}Qkrn`vcrres7iN@I8#KZ6ft0*TE7;pE~>-AvK#JT4jtSo z{R}fpx646wUg*SBe(m0+Irp2z3tIZ9L?JlDA(hW7;^SsOlrSrlou(EGE}oq@%=mSP z;#YQxU*>+q?mp={BAw#X_7%6*^!6MgHX7`~lFA1$pMLNHp0jp)>fhHNKf*zl!SNRrh6@)!zq?oIOc)KLkDSR{IWNG5%fZw8d_H*OKltAV34(3>{^27Yr1L&J zj-|_J$}WTBkqG*Yg@IPQAzn8@6n`3~Er{S5vc``PF^1EVsT;YmjRbfHq8x*)xgORfFyG-hL-~i zbi&YZ``9r=R!+*s8g>W_H|JbloSeG%0-)RmnYQfR`bNHVdxz|Y1dRc@kF(@bqJYB$ z^<=`Kkd{B{96PC%84TL+LlxX8Ky!0RMl`FE!Ph7>0Kn8zZ9CVfGmZuxTMiO)^~6`) z8AH4*Rt`Cn1UF;tU~wxf$mXg-B6Rluk|DaN9Jdy=xwT?GOPw9L8L8N>a)?JaHD}{4 zt~IX-G~z)HLX+GbREegA-YpDb3AkP5_#t$7Z1m5&M`cUZxxI3wva%!i`qN!^Dg{zZ zMcQHu#of_DI=1-GuH;PN3-d9iGtB1py(rlHkh@KLCXQWJ56#A-vk z-4OY3Ic|GKkxl2L>S=6pgw;~~X!PC2{Ch^!{KikC7T@9O^X~ZZE8M*DAGi{3)Vdo# z>`pH*O(BOTedtRenGy%pc&Gv$ju@%%$@v*RI~FLHxBvac5R}FUAe5H5kHKe`N6H?+ zkuPJpAI*F#iHQe10_hS4qj`6a` z5-of<>N{TgZ0YDwPDXlXvP6XJdP*-$p;hb9$e+LJHJfYWPxDp*Bo^>KIqwo{IQwAn zfI|Hm6mI;0-ua@e$gcf|JD=UW%_jLD`-J!ig2YGUwKUcV2=?{ZUO~^*fc55_ zO>nfts`HK~SU3C50e*!LL5C+6G@7BgyB!T0vSKQe_}NHqWK={{n6jwHp7Efu$O8t4J?S-cD+^y4H%=N z!+RV8OI)YlK_QS3I}-{{e7Z1J%WVzP7884Yw1II=bZuXO4h1PlUQJ{%Dm3(oCy9ye}2JoNsPNQv=UF< ztUfW7OxZI{OfuKP>9SK;dZhU_NuxG71$7c$jCdf+g6YCcWNWbv*RJ#c_M5dCu`?rQ z%2SGfuwMXMz~u@T1DB5WmP+Vv<|cT1^IQua;SnI8=fqvc>FLf(;f4JInAzfIDUi58 zllkD3RbD!TpENfNT-9xH4S4?KI@AibjLS61MpBLN@~I1F3@g|wtEWpp_*SLaaWufUymI$mWg=|yDmiB?B}uFi}wlAPg`^W_sWm-8T=mf9<` z2Gj+?f<^WJ6xw zPOg*_*Mw?G-!B88uYi#%hv;g8c4vERAg}|$pzpt3pSv6%Si|$RL*q3)TZ;YHWV#AJ z$?OkMh$G+Jf7SjE7j7Sd?>eshXr`e1_+Qo09w_rVOy1JCfUlZy5@hDWd5{mFf!SKt zQvnm$S%8*_cB3oUWx8D0KdNibF>z~eu@MyyGycWXr%yjH>r!A}EH!3aVu>$1HYvB# zLA=?%+)2QR$iVUr3d$TFPbl^)a}(p$)RQA>K?nf2E^C&lTh>)~+yA57_OGV6eyuwr z<}5~;VY_v*znGVVwl0ow?ZTvk2uze<=>lG$J|jrlAXtg1@9izH;C>rK(nX9Us~3m# z63}4L7`J3k>Y?0lVD(bSsOSO;rNV4{9WicOkgQXAVs zuw5iVmA+ArAxAWD%`s(*u+z;Dc?OFwf`kBp|5X#YN1Dn`$f58tb?n{x2 z3ml4t@b9c{#}H$5?r5 zaRu6TTe{_wI$%qz1`0I!0t1UL*Kq9AVkx1%SG#A*7Hg_lQ6=n3C}J65h+@gWb3w0=1A- zDk^6>X+m|>^LyM(Fo-zyz0|Pf=U;I(Z*ZNAAHf3Q7QB|R%siL1*W&sD7MI29OmTqK zwfaP4sJNOe<0$o^(vVv+XMlPzaIbMU;`xgdlF9Im#BjbN7jsppHW2)@RTc3HTGOdn zm&NL+%y0(!4cgmmP!Awe+@ZItffdN_-6t1jZrQOsFafmcDMM8BeNtnkH)HzaAZ zjjPPay%sKl=r#`+onAUZ5XGS!b{CEw7=}88R);cpXC5yHjUzygrh05EEnIHJ3;x=Z zChjG;L6pJdP6gVSB|ej1&QdmQ(Y@l#hPC!eRPPEZ9|h2@J1>G<HjjVHvB@& zk`3|G=2^G3Gx)K$4>((BT4}lRup^;Pl~7)Ya%D8M+e#LB4mpPd<)3tQWme4 zlfQ?lKVk78J6-`49J?cPckuPm5w_rmN`p&dn?MYjT3lJ11aYf8GMZ$$49q60w7Xo) zmha0@jTIU8XThnJd70M1*-DmvcC9{4!tW4)_U*Frb$?Xxy1&u#EC)n)wsn0^8UbJE zpk+#iOz2;uZSWU%t3_9^sQ!b`e;SWpE#Vyd_4rF2P~r9;LpSrNrq)WJ_8w25ze(YM z>b74Xu_zAd!`@ZtAJD>{py)ke<125`w5TIIc3Yf_zasfkf$$RIWzLAY7S_S)b9fKW zXoewv7(LE;fsI!)PD_MUCz zvwMK4--0Lc0H7FLTt^xbEWZqMJ!dt>1FUAD$$ovfY`bsu%*TlR z?~V?{;Li9ZWHIhRFTTX-_ULDgzqdwiyYckt?oyc|AKn=1Es-e6n<{1Z>rK5}TqreQ zseeb3@;@GgLfU2JE{~UCvl`qe_AnLps^5!zg{@lk-mlBrgiFoBNM5j&Dp0hAGJr|! z*mz5Ybd-8AnoQR*BtFe|INNpZSQFD}17a(6NQR}ajY{halR0zajLdTJR4fQ!0H`cB9dKjg?9Px%UD~$VDP>jvBEuQ9ZOrTg&pG#=dqQx zFZ`jtk>i*n8ln>V#k}E%)BPjNbL=BWFgHpBxM~|E6L2srz^ z4J%mC!?#a;%NM|bM*PGBv3xKD9*vKVPGUquMZSP4o^ZnPCTE&)+br5Nb{5kn3}*+F zc~*||0fTd~Tcw?*VVo;*DiB_#cJ><#78-9qcmtc?A=XT}9`Xb*-okd2hJzoVDD<4s#vf~%s{FkD#1Wyhm#|JX*RK!mmo$+ z<%&Py8dj483_{XMt*W%25?di2FiN?uhv9$(=xM`&YKMHcoZ)sze5q%U=hgCwmo4zr zua;q(mObKr(S}%hM-k{TTXTUiQs$5Y3%VF#$xd~|R1YlS;%6(5Vqi-epi_6l!3oMt zUf`_`;5?&BPW3<(-Vq5+(g3CK0ZAKZLF!=2i%#{5DSSBzNS&T?DvLzAJpdErY|U!z zZ%QWv^SSM)ivtkq6T|b}zjSM+f?qUwog@hSCnK=*PS;-u$sRf;>N}qm@ zrxp;+{q@)$^JDwIXt2argGD?1sd6*SEW5x3`DS88LN<-H(C(Ig<=iH*TnG0y^abUi z{-lC_mG44?^%KAFySE{-MnT&KWI{pb~ zbG9ib5U@f#K-tyD%|DUr4qrOg1C+pmc4G@Y;3|A>`mGU8A{#DJ1Ln%K6>!@{T+Pf> zGVCC{t54Mes;WlJNeyT^PKFdzY&m!;R6^_wyGh-*B5?$iYN%meYoVn+%FU>R(M)*_ zOBDUXojZU0v@7c|TP^$hXc(b-(q5B zFudqSKEv5@Ri4XoG{N!Jx-V7Q*Zr!i0^t(AlGDCqf`cJ?A$;8ytUyRI%RnnVoJ?Pa zaOAA8$;Mm?$%fsS-EmJuZ`p609F<#X*ua(TK!c<~|8Uvvs2Tin97XW_j~JlLhuGcj zjLm0HoSkFr$T6Sn5tYW;h2W1idCt=BG zgyY=@yjACuH?o@Ba`jFMc*SKo)dLX}4_!dx+;N{z0MrCePI>LmjC9HpAv$3Yo zrKiJ5o2JznR-+swNJq_0Q@1#cY2`9(bNX(dF9zu4_VUgNt;6rAh4}#X=%IwjXCOL>QP8ji#D{58E)?h+pH_g7-Z(j+Z zz_KY<7DKKv$UR$mH0DT~sJxQQ{U|m)K(V+bRqvWQT4bD8vY7iX~3%}aP|3v^}tH%nx-t;Q*KdU*`Brs5GsJK zC?~iX6vGaLw#f=_HyAB8*FwX_6U4OF8(}lTeumdSKG#-GjqqmYmw33SCbTa-xpX(m zbv+j8FD6_9H=!eSJX-los&x7*_;q-N>;voR*{8h zkSxy5_1cj<_pWASr&fRYD3}8z$>(H$xd_g{W4VxL*VSejQWY!X;J=)Ua&%q8Xy60~ z*=d5W<|g86Hycmstm07_#1sbgSb5`Qo76?3TuI<;Hfv1G2tI8_E5Q;A0Uv8d%KBi&YAOj!{sqhZ&OE|NR?Xd`4>4ohZ zDKE$S07i0gn+Saw`y942n$maQ%{19v%%xSpS>$!1@3E~Sqi$yqj+tWEiX$S#_kJNK zm}I7y%ze`EaD@;75m_)%52Z)f_t0tFJmMMP@mtUv-A2zahxEu^R)JmwBcNHmXx|D- zZI4+am=iTmKu*{uMn54vYk$a=mf#OJ+D2IMeON&)OXIr*Zyw$wtnSurAML&!9_{Tx zh5K&ItKfVOTv4=w^&GO46j=f1%9s=MMs_rgN5?wJx(d+}= z6bQ&U_7Hma?e-E3FR&uwMh#@32d&Jg1?;##j7uTJ+t6q+fB^;rXB9@C4hQS`ig*CC zKnXOIQ(&_d?&wpZ$VyZ|@L~@!=UWJGu`1C1e4PScugbw-x6cbdi1L6p%qhr?O)88a zc?U=8Pz7{{foE`wFFFB{=jQ1qXxHp0BlZM;djVn|4~=qHb`D>X!O6EnFW zAm+tBudt6zfSD4*SV3~~>uEKeUMCkK2}HofAU?X*!|V##X!FHOX4P0@ppg+q>!1pm z(|F6-E_C=Ir5Bp4POwPc%Dxq zxWI9Eo?HL|X61L(>IbC{w!s?W{dwpPpu0hvuN}8g$t;FTxbtk z4w+Xqs66}5?A#D{o|>k1no^;3=dAHCvZ%lVG-z5Um#mm3=!{ff$|vi-jJQA`JPvl zPe}u4Da(YmFr~!k1yu?dh49RR$&D(dEk2q4aQG8mQaN1p)rrvCBvg>o;|vjw5yc;` z7Zpd?DXygBRMQ9JDFcc@t}U|H;nY?R!eFZQ@w=a=W|U<;l?u#KsSG+R^&=>AWNLaw zei%LczFe9sNzr^x_$yd8VZ?+5;t)HX0R8H88xbb4jPXrK({H-qKD5kAv#ejXOp{=~ zXDPiJ|3J&ETgR~t?n+VByj$MU1sZwwpk}i76692EYpZYaFfUQRK7l9kbns&TXd4cx zjG)BGB^YH`O}9_?!()MT7sFFNBtkAy&%P)s!OqwLFW@j`&7~+dUAiY3p)0)XaEycP zMTGgl4f5*)FiTm{sxzF>8)SCBkpIy|YS2+J58x}Ld0GDu&!~?#{V&XVScGx+gnt(> zHVgYlFBYCvmTq_--N!t_i&1zL1S$_Y0wvI?FQ!(!F08FM8QmVAKuseF@ch&(s$mRp z2E}cRqnNu-pCT-O<<{T!uTRH+o$_D2K4r~hPikAY7SdGU zIaU|4`&DPj^UI5TRY?$wT!0Gxy1>Tdm9|dO#H)hzSBIME#8r`ne9zLmQ4PnX2jl4n ze?B@zd@*=j<2-;HZw?1G-8IE|#xn%1xfT^>dHTV_5yJDxp9Pw%qG`eVtn>*|0IIf5 zRPpTB{?S{4=dhL{eNfk7JUO6m5Nq6;>HVjn~ZN5Q1Zm^<;lT5 zZWQ~rJLZK(G%j3gH7tu2xCrMV=%ySO*=xv-53YX@v5L^xo5Abbcu zr-Rkk*gSw}O8qxJ_Jt7ogNJJyOh8~DF1XTd9@63ik(s(6<-3m+3;8o^C}HmS691kU zkBQ>NFxaL{aGQjPT6jJ7Rt`J>4`pCNSSC9|y9Xl^BXY4DYY-TrpSz%VXQaZ`35v|| zF}Fk%E85FU4*5QSYFeV$8lFLJVL>Gh;_~p#V0*Ol6Fll*&Em=ftI+mje{%A6Xwcco zErI=l^d+~)io#UM>Oo&lLo{Cyv#&;maQ>FR4$rgTv~#s2Ml3JeEXA7YxYVD9DT{qI z*bHJlgV<11th!|7L{!M?eHd6j%NZAZMa(%pSy3g$gWR-#q;@}I=ieBSx!xe0g=i1e zQien`2D)n(Tm?BoEH{;hx>1=dM_|ci(TR@f)$svoZTI8f-T{oMPCOj}Soe%Dl!8G7 z6{v>6;8-<4H9^%Bw%dq-StWGivN2xE<2kE^Ik&NjE61MY_*Ls$wBSCF&Fg-2FW&YMg7{Sn5omBAoa zUur6~2=>Gk33AF^G8ME5YqF>4(c$8P3Sx(XHF)XdXbB3@34;d3z`{LJccj;uo^&^~ z+{;K=O)*hi7BbS@3QteBr#r`!?K;NG!6~4EABkcOzUpAzohT0U;%C$>E&5WxN%+y= zTLfpJ8iD{zh~om&`vE?&>cs7o0oQJo+~##^NQT`Kk26TXe3kh(u;u7r@J``0e$hN_ z(!cTedA|%8W#*&7zxi0c`v^#B{fGtVJ{({nR$sxx7TCRjLnA!BwlF%In&p=Cvsb_W9WY@B= zLdcnEf$w(0AV-*t7)lhwcn__Q9A(EJg4T5ZqhHu?lO#%gZb$H6{$fzAzzk`$eeqa= zSb})Qp{2ioHNj&obBc4p~n3oOqV@ zHY{FZr6hB_Nd=(^pti;KULZl*8*R)G6Dco|Y>sOhTFA&Q#P5%f4kjSC0_Qd$;Z9#c z!q*U-0*wQQ=nH|;3_w~Sq4(g{7|w-kVjWDwrCGuzbJ%^HG2t8q_LITt@$u2|BFqz7 zCZ8!Z%Yap{N@8+sC@>$Ie`uxlc*-LD2ka;AM%jkgDWruY_Q>!vuuM%?Wo^X?4dmKm zk;y|TRIVCUFq=Th{4GF44JndCbtV=dNR`r-K2ab-Fqb+FRiQ0J4&2#w3rnE&=%}vV zl_ezAo|PSL$MBY{&Z!YVGi(nyIDLnC#4Q0%Zg8GucXr^JXHfbe==zW>7rQ)=2Ffwy zx$ryZU9mIItt3cQHI_OXm`X##Ig!kwHQY>F!~}?FpY<5#K*im_12F@rYyFsMrLw=) z4b{nP%iD0jvz8~~>fxLgK$@9;WLgE=Y1IRJF7mT(Wu8(vy&+B?{n6{bWbq>>W68wD zPppE)cHd$6q31UMJx$QKyy&>DfQ$ulKF}=DfX&o-fI(nv+UJAy{069}1;{zW>0)|j zNSk!TQg*`EOMqMQLzZYUKx=0=^sSj6s>$UbJ)<@=Y=nU+(XyfdeF~CsiMZ><}=+aE>O{1-21XfKw#&mhg~d6=ep|z*b_Fc5rVom zY6VkpG6us`qlXJi(|xRXWoTsw2wn41QkBw%{=+y!9kQ3`Nb9}C609?{* zggGEiJ>S-{DTxr5=ly-jg}3cag0dfNhXggdoDgs>!`lb!f2Qq1JHV=itc4r0fG%ht zL5>CfI+qUf78a-ty&Prb#TrTP4wsOD&uurDte&!&Cb|piL+6B6i8EIhwlD35Kb&Ng zjG@%E=9;4O`Nf@Bqc922w_K-KFqQU6sFz(#%>*O0+K_}cYkfdRsoB~`S!;`asvZ!3 z@sV8&Ru_tsYEs;Q87$RnO>N{=H(5BZf~^hilt#owLX*yYp7~k$4Xwc*{(dreRk;H74%t}|V`j9rhffXwXH|ugcmC|!O_{Vw*9hbr8 zsnUs+n)<;{&Nl8ngK;~TaZeAUnVNO0RJHD1ywpIjFsCx&=JyRi^2Ze)uSNzAqeo>M z>0IcgD?L{<0XXYx5;-(Vwhn13GfU9BjJ?TY@#$|caSB{xV=gLkk8xxS3m3f1s?i#{ zFlvCb_4_$8EAU1M#A(qU!I9kj+CacOHov4PxK|o{nh{AZr>*hw^fC)2n3xA%!_HN5 zX6EMjh!QTqH4L{TeLjMBmnjryndZWcN#G0mnGs8qrhpx^~tiS^00_V04H8 zw_b>M#u;;Wyjz)6>yxZJ#3BS+2?L(C0ZjIBigcV7a@nsZXvvyS(CSLc%&=%@7C=ls zIbxjCVJ`?)UopFc`z4r2uN>hlRvpIA`xEvPSUqrF)tWruj3m4)TrAz&8*>P_+DsKN z$v}zw4I759i1jzD2NibKn4%Q830awNCF12qI4d;v1)7)U^#L*O!VoAAxu+jE3@}zu zlV+dnrx9}l2Kw~-z^vd7tq|C#pe9q1?#=a`0L=6i^`fO*>dNI~grNz`*@u;}CwWWgIlVR|-G)vCsoM5gA z@Q)~wW75}J3=Bq~(_A)SiwouN_URrL!jN3m6E%`(Q9+(c3c;K~o}!T?1mX*BE;Mhf|^MCuq|v{(3aQF$E4wOYCTOlmZEG*|0$16AIMXXCF0F zI(4Pxil>dAg& z1>*Y?MOuzm@X$lF&&3RfgIpM}mh93w^(}UHH10pQ)2QcknH@X_{?CV`3Hq>s)oGt@ z^04M3Bv;z-`GN$3r@$1t@2+_uyk4qcNH}}y2-VpGSS@jMjNA98xJ8cZM7nDX?_9iu z04H1=T5XEzjIXa6~mIlcuyZGl<=sw(ZbHSze z8IB%cnn%JA^w4hnsvoA?14#5P{7eK@qCiIaEFmWR{PEYA=`S*GvDL! z-%jDph4Ys|6n%BH{}wTf;Aq5$7eHHo7o?{R<^~Gz4iS?Pv~im{gTY{ba6pr8)L5ax zU%Xm^$aaCa6Ob(VO2>~}Bl3*YQg9cGyqWn}s`AJ^6XP-$A>k})0vCb;$Pye*~0>kT0{*0*r1xQD+Z-aaCwaM1>my*$&-7-7+e)2Bml`heeKCNEYW2xxzNAEb^A{0c#p)Y1*llWX&R&U5+ul7fU8l9;d(yGf8Ibvn zmWt836W=E%MqDmH8q1up_5-MTVR@-khRs-QSj$3G!Jj-D`MI7@uvbyDM;rfW3QIy3Bi|*hl1%YpqjYXA+A7k;6x{TwP<$Awj&dJlanX# zHvM1YlAvA5LvJ9z;lewe;KWYn&@2YOD+YUo7nJv4QDM1CKet*eq1T~<2e>Z>Q4PD7 zo2I4L0X`ly;ezwy!y0)mIYA%A;Bq0%H2>LiplvzeMc^p^5lawYUPCn(F;NXtlk1=z zNzVGJy6?sJS{+p1mCo1)aMGbK=Ixb+bWE3bCN?j9-f73QT>~}*^*iG0{jt$}eE?q= z-tqkqjzCxp0;gGg94Kg9Pvk|uxD!-BrAr$k7bX3<9K*Za*aqfwX-4Zr2v|dCL0yK~ z4?0`K;W7Ra%Jt%G+c+^nWh$SQ2cELH#pUk$01+l6dhp8^^AtiH9FnTG)3U!<;`A<~ z@9f~_gTV6SO{{CoFOn4T%J$ycO192IXEX{<k$JI0atI99>FJ-lV zAwRH+RZ$E^*f>8I6&w^oj~F#vq!Jr=jpAmPn_{;D!gP}rpQ&xBtSXkIyS$p2{?S9Y zSvLL?r*@qn-IRp#U2qMyCqyDm!P>$Ele5c8aES*m=X)BV%5x>r74ox^z=m`U@{^h% zVt<+mBC8D)*$YMqY_4qm^05e$tj%`Apjy&rTUtaez{Ui{*J4oGgfH&Li{rb}$GGM~ zv(J6*;$a$GttcLWQ@ku{5#_RTz1F+5+XZ&r!O(t{*9r;G)njd_^wz4`ad(FrJVPCx z=$!pr5j?tStlU^pP8435dDshdozgp^v^(=dcL3`KMBFQ}S3&R?ux7*Uw~Ewg36^*b(OdTyz$*&o+y!@_JGHFEp2|*8G{|>!OK) zw5(`9PJid`ZI3#{HgVC)AZA4+M~YmC3G69FEoQHx4B1=+w6&@GY6*-N4;hRLwA)4V z4wZf0guVO<)Y>Ji&5pI1x{A~foN4e%mu@4E;H}2^HKUX>wOSJEk@Iiv-i9CQXT?R8 z{I|wk;WWXY%S^}@iWJ(e{V_9+_Eo!-)d1M``5@ zf@+biHk^Ec^;9p8MF}G;%)>TD)p8I?q&o;YBFtmW7 z`)N+&h7LDb*Ts}V21>VfdA3jB#=uWmeLf6_+CTT~1WWtGv7hJ45xDbKr8Las8MYS@ zK>q{T$=SLc^g;sbyGF!{&}ceev8HskGkgstCNqZXksRxl&=GMuTJ7`l;3nI=T7dxK z5Mi?qab^58#q_f!z=8Ex%Engu_WU0)}J5yRV5qx4vAE^E+ry$ znuioe%)$A5xK+qmqfsZ9rI*CDEs9%H4Wp7&4O2-3+>HJUXMLkmwM8>%E7UW55u#w_XNJF{v+C#7ahEa`>kc{Us`h)X3*``o?ZfnK z2K4JfRb6v)nCQLFTn2I9h8Rp~ffz4NuH(4@FRZ5UkETnuRYu$ICgBb>T>6Y(OmWyU zb%+M*c_wZz7+b6h6zy2b&IfIVybGG7$!Al}H`0zqHq%H%35aFcF?k~7O9Ykmb{$Y9 zzg=YZ#OPvWP%KkJ78a3mV9&}HvckOA0wZ~W$h={ImAt2djR(7h=oddKP?Wj_l?AYf zKe{DDx*9`_F5T7lm4^9-zbAk!eg;C2Gh^X>ZPP_OpTK6)Od!nxdt0kMV5e@6^Wx-H zpp4_VVj{%~xzE62I4ak@rTx+0-!Abg5>H+Z#(ZXaGWAz`G1rBJPVv#5WN1#F*wa8* zs4LVwh5jHoxDg0%trSg=G(7tW{X0^P{~@`!OXvnhz;`;mJ}`d+_v>Jt@!=`r6j%2> z&{sM;@twc@uy9)gwdKVJl2jS-xYD>1hmkr9;fPBkGS+77G_No{eT4vWcyfu3OQ6IC;KDjXb?@nAO&YsQfGk+G81PadeN%7rI8rLun3c$$y`ncqGjSSsKi4mJsO1sxKll# z?7U}5u|y_qO|j;}O4vS5zAioV`zjT~hNjXkNDb@kZeV8(>SPlz6l3*rx&*5vY!M1x z+j;Si)zR;~v+!MV(_^8O-?rIP5zE!;aD1AD%4re^-vDv3K2p9p^EsX z6kM;&53CIHbzAAFF%U7>_Y`!txh>tDJSl6F@;-ZtmU(#eC>g1q0&-<#6f(}Tdd9x9 zDIMKmNV02@dkySDbfLQPp>Tw(4Wcq1-vc8p%i&zWrf*W;PX!YfgLTmpvcVOX(KdQ{MNxtXoBJi$(_&~bsqZYrnzJ3Pu>?~v11!U3JwJTc zYsd#@$ec-Tw8KfO7BN+M;K~#0e&({g|7ET2n&oV2^#7Ht6|2}k!dwC4pTu6qSH=`A zSEbR`mM`Z{GqFh>vo!=eB{(Qa0*6n2ShrssVWWswXGedZ?1wMV_IPJRDGVuH9%wUt zAMUenvDt9*FL`>NSxVC|AA)r}s+|&28s?8_#UsBWQ8D-1+2w$A0uX#qi{Pq4t`*Gh2V-VADG&s8i{N*iYaE%G^qVXIQr zRJN0=9KfyU(vt$LVS`FX2PZ1M!rnxDFciE$Mz|Q*F%Wi9tP~z_Z{c~ZsglHDu>B)Z zAs!U>eXdzM0)F^TGv20ecKhbhTR(ioYk|PWHC1*l=hgWp9dFV-4bHIZSRcA39OqYu zB0Rcm+uc7T+mik>dUjFFbeIp;^))|)ste`;^bTjvuHO^tY(6uIXAS{ohmI?sZnb;p z+m-K3&*vSI*3H#70F9@qI4jP4qk`s)2qR`pc@Q19-Nmo$cBAUloo+KO)MZ1Y+hHEv zyWlX*59T$Hu&?_*%MpgleRb}dexIJlZptd^ixJEfeq$l=B(0B8*_kKnx|FSH9W|-= ze{15JHZ+>MyR~!E5(Na#xi|GKby@@G>gkXQFL zg2KyLwTkMMgiXgZt7Y!MoawHya7P8Q?{i9sxTD;BXQ&cX9J3q+hM{Bs8X8o@jKi;HWP9vftXUs0j8j+=nVUb5V)OSz@a_d(n}NEfGG3&z?vmhsPlkc?1-ULO1CV7Xh=3$yg^=)c|(SG0)D7d&3 z@{}lMXu1XgNZJBdtQ{TkYJ{UA4H$VjQT=NLRoDF6cFzd}kCC&yV(gHzc3H++Qpi^h z`hLyGyAy?DV$y`is`SaYZ|kX+2e~4?u^}}o5Aei{eCuQR2)TwJae3)Ui~(%<8sqqt zKQ%v?zCGND5LTRLEzLmJO2H$=z<`Z$!I`2m+S*tu-exmpuN3slw&l6Zz9q!gip&2MKWb z@o#;<3^wl>o8JutA;P(>BAoIL{JboUsu=Y((=fL2iq9S|w#c(J{fL-pTYa*ENm7wA zMKuD)q0Brt?A%;suurP=?O?cB4KA%P8#^sY0DO_mOqDBB$^A71>WapY8F1hAFn6PU zKG#HtUGNO=(+xXU1k2?|zi%h+IoSKg!@Qm!iw(NS^`;|7)fM$fOi+Rcv$HvWsDtB_ zVck!x@p}4!E~h*S8(g(2rn>K^)8TwT7+Ac(V1BZjP;dre6LH$NQ-K3;vNK^|rU3?> z@$t(!m+3fp@^t({dUSU>a{`N=yc+LXXNrU~ElQJ_fn?BLFmoY7cd2|Fs?&Qd~Vb)_D8yIt$uk))au*j_X1OuxY0rZnmrGY(IQk zjQ0I3!p|}~y-l@mwqUor&S24|W+5E^G%lR@u_z~J(kOsjQ`JfE^k;C;E;5O*pS^CP z{4*QbI55YOX-|mrYO7V$*`uprt}TJ{#0SIIELNQY`_?FQ0cuxDvM>!GeC#;LxyiEU zFn%ms7vud>y2tbS_hSF(Rz_?jmC4&~#^x0@99p8&NPw@vAzp>74l!98chML-jK!9g z5CNMtH&uxTiCN8)a!Oh=ZVhc`kR>K#Q|12;ro6xWIEfO`Hg^QdhKTbnYzp*0yh#m;*6~i)moK z^pCQ?IsZ%e6q$*G45T=Jg-Af3LNsxa!_r`#ZDvNpic|uw0OyD2i){nd@?0aL%X-Wq zOg_1=z9n23p@u#I^{N##ZCX3;n8hmjHVi=XA{ddIgQ|>1KJiu~sC+9Eupj#EP}fw{khvUxXE{vjPV74W*& zKP_O>=#`5&75Cp~SICuERr2fXO3oCj;=lVVNPqL-)hX9gaeIhJ5sT=dPj?^U_TmV$ zO~?F-BpBlV)&8d4>EqE8B;4gcik75bG|S=t2IFoVrlH7GOK^>{|+4{_>v zymC@-i7PgUD``hYh+SGWm=zg{30dBv&r=^lxYA}h>l?|BGA*^Rz|E}MX(Q!J$GjAm zfE)=5T$38;nwzuid-^DLzz-WoI-z*EHQWGZx96?Yjz^-XV=1$fKmpJVZtDhgou?lx zUiGy+%NLVLEa=`frxg2&**<==HJ;Lq`yI)+PMiH*kM+X@w@BQLACd+BJP<FJ_{ z5D?mF7ikj7Iq_RD5ZOIqC9-;CfwJbvJ?O=HktoM11R}bOf#Pd+Ixc({!Hm3jVk051 zUx}~296kMZd~iC^-;Sh_Hv-4*(dj;2pPk0Q08c+H@MxZMZRfSYKfe-05oU3hko;oj)d#kl`ElRyiMr-i$J zhz$ia72@so~jFE>YzM3W1m_zj!XGWl*JqN*BuLO`$ z7lId#;SCTo@VOYQ8DmjZ$|%ok102YC(8q=Ido!8dBX90!a7>B?N8-vAOXc1Kn+Ukx zZf)ILd30~}!Pb^+iq=|iY&>Kpj(Kpji-+Y0pT}Ez`})St_29;rDsT^Pz8v!r^})Zd z55A#+*!<1u3}dezgR?M^U_Zul7X{E?r_kD?w8MIW7n%`PZdZ>u;{A}d4ZNCTkE-<{ z;CY6}*Q$sxd_Q0&A5Za&{doA-DV`?#=O5MKXRprpKNWc{@)E^`okeFvXJnM3Hs(Fj&4lHqvM^IU;XV1h)@OB8`_GJX=RL=Ud!3fUMEJ z_u%m(K9sil{nj@RR=!0e%hDw{N|uM@jmW#z$y@*P!>{?inpgd};xKi09wL&8!f|vw znS%Qolpa6)eg(XTe>T?eYTGPcUf_pEkDq`rtM{YGt&6sw8v;C&JJRuQ#rS`Evhw}b z*K3awY@tZW`j6E=XRApRW#9YZ$&){Cef=0r7bQOKE8*SxV_)8rwQs*mqA%ZRi*)F6 zy9|ojkL(7z4b|_^=}@mC98b0JVSBJnNacK@KpkK3lDL_ zmkGzs&+D+xTlX-W6oG%d zSukVz`u8i8;mdb=I1ehWIe2i!b9c!`cxRF?-68(d7(O)>+dWwMPmIahgN@ZELHxpa z%6tgE^g%0QuAD!8xAtH)@@{u=!Ih zgVJ-#y7iTBR=3t3ZLEGP(e&BPo1ZR!_SvmZKK}IMo1cAFFlX6PYiYD!Yxh(>q1KM$&k6 zSQWw|H|`X=kEFW9(ZTAQZkzWXKSUye5g|%?RaQHz4mhclRT&E3PLUqu5wxLG=v#)I zVsyNo(y+aCO2h6{wP`ZGQ^aIkQ)<6Uut&I5Ta~cU>%cK)s7k>VkiM6lV(xU=mV5Jd zw$z(?z~Od_J#(kflkp3v#T6u6;p`MyAD`6uV$*IBCDx_h9&FFB%(@b*QmGkt!2J+g zrK;@D(f2#(mJJAxb?A|3Nn?rA1C9VJB7jH zO0G)o;Xd}s?OUCK-&m@EcMIS7xUcY?kGqAT)&H?mat%p6#g^~PmRr8lQ*Z`P0K9#x zTky1}VTkzgKOi1J14hAakS$)-JP-cZ$oQcW|(kz--SMoLX2zI$*eDDg<8O;U; zI|OwksA*8qxR-&e#V(!$hV6^1D?dpurcb(7N%;5G(v4MBY4>C^44tyhDm zPiZ?}_}3dRa?x&TJe=&}DG;x)7&We<3aiemwQ)ScqwCfXDvh5$T^xS&)zha}->caZ z{JP5ePoEyD?YUk5ZsXwt2JyqIu#8I&bB9uRP%zq|nWNLy>COlv_}$3?eZFq|%i>pe zF{JPJPu{;cdH=W5qm%c4xc%AHwzEIr;%QTB^Ityy5|7|KYdZJcXu8@IGZ6&O@hW*} z&y8i6iS6BbfmrYkz zxydB6sN@+1*SHzS3jkU6i*Dh$$YKRx&}eKfcn%Ubt4Lb>>dMon%U3u5f)_WQK6{UUo(`{)y_T=y`$omcYt!%d zN0Y;ViV8n}^kH3qIW+&X&CS0I)zmdWWXp?70J(b&zW|@Vu6}hju?RG7&7c7sZV`|7 zi(h?VbqNm%MBV$v><_PAz44+DP+F>6AVEw^>9m?tj_c@vsm3-^Yts9>XZ{GL=_HaueJqy95(txIE?09UA-2-ru<0=08 z%ZI~{u6?z5mH5B=<^9Z@XsRS*m(+8)8rqm75~ntLh#vW?>jkDhK| z9H$(m>9r3V&Sw5P9)@Cg4J%ZSHFHbppJ_YN31ktuh7!XCaRT)Ck;dSb#A0huLxa#n$8ZiR9uhzI<0f2WXF$dD( z@EVzmuxb$NyaQOlxc(LFzh`vt=oq^wH-*7GjxFK-E1W4Y_7AMHg}++yx-#9FO#Xzr zM3d9+&CQ!j`1jTx{<%Hk&yR27pHH^=^A3N0s-K_kJ;Pctm)_f>ou8)rusT9i$ja=( zqeo1bv<)65i!Sn?t6$aN`{q(iq1E-WS{6xq`FRxLc*z&!rTy_6ST**SMAbw3MfOaw z)#*ko)f(v!G1!YH$bNbDk$4CqA``BDgu(u$?plXaLqOOTc(4b>o38TM7w;U6p$YIF zu)l~a<A_S zFbEe~LtAKI7dBT=n7{V+_KF$hc#4&28*lW4xplJ#w?Jza)oU;z^&x}w+2)F-H@y!=*&dw)V588jPouxL zKHY9Ge{l5k_&5uXmi|sUzS-RqJ;k%Zwfx&u1&6(S{3`3J;%G;IwwDder~0$^X+0*7 zjt;qMwe=i5Eud&fODO(w5yc-Zqxj2(6o0go;&0oN?`ik4&}t2Auwi!oW;58+b!t{w z7^=k6r`VAJ^384j!7Rn^ks3YS8}I2G`pDC#;O^w_io;Kr@BGn9FaPl-_Ik>?X(_-$ zL?Jr2BI|bi_&9!i5WfcEVH1Y4auKHtVq(BGn8GbbE@HK3vKLs(5r!{wwXPaSX!pwLvv5ZL1$~Yq` zBp7i$_W0=ZRaZ{nY!dl8~ zy4o$ODO(lQw^5~A^#0_5fYNrLW)K z*Fg9f;zUT2LLCf_r%fxz(~8TwjeavZ`8yjWgF#&1-oXmVUweDhitX24L-L15yOX^M zRy)+fI&QccaRL0jeG4o;uhygkqg8|3+sk%zu}OpN8tb|>W%v{vcgJ@eN1*%c>bqON z)UB=Kq~rS$)J$@cR}FEqyNwE-xRZ%kqMDwHY^rXZI)jY=`KNzpK{bQvzuR}X*_|ZE zG#htUQ8GdDOp@193VFpUUGg$9QO>HCa!%F9uTG#oo*d7%yu#Uv+JLwFet-Y{!TaO! z`|10W_pkBN&Q~?P1I8>06^#4uA3S*f@con3_v`OB-v7AT!WaVv*b9_|lnORO3 z`l?|`L5Pyix<&sTPn@!B(t{&q{o$Z)O8gmD!gXyL9LL|mK+lHuPU?F&_M+xhV+No~ zG%)=FYvz5_P~>8df7oOAbNl@! zmV&Kk&Fp!6yqly|c|lv>cz^5B{r9(@-0wi!_^yHm?V$s0ef&3(xvv|?Q>2n`l~i6m zIQlE2Wd|WaIF~w?BOBVSpqgUVf-O>lqAdjr1~xwDwa9cE%9$bSS+h*b9)Z6RO!XD^ z^{oOeru_oWYCOhS1Yi_|=O!M1D6slA@w)1Uqgw6?b|)i*ptY?DFM3XG4?m?b>~Q$= z1c8gjC?hi%zizO%s=9T*RNa!oi#v*k3M~xRRNkhW*MyvfraBP%N1EG$=f{@o%{@i} z4GZzY*d>XS*rid&8nEfRmKh8&94{xM>GoULC8ope@eM?78c%Qhb@Y0~IKHn=mV6)5 z+1ka{u)-r2AIzrCYUHbvvmN=1{MZ@Q4#uE0oOa*v`EdT!wf>)JoND>S@o>|V(_~W| zf@V?*e`Oe@K);sKq!PfAPr@D3OezgoTQGp^hYK_8?NbU;GuHsX=)g`KoGvr4Da-^x z*qzf-Lh~M#g=@BDgEvEqKK!yLA@1sg7LF-EnJ)>&HY)1O9a^^<88f=G#^&G0$45&) zPauc~l=$>e)u1D+^(%ZsBMjpeoIbeOrRN`Z>BTZPemxwIZ*1=$y|@9z_LCboKfAGf z>&7nT32bi1gt&CH7mR$P!^t{_v8{G8bLhafYK3?+B~ZhqIaidzW-Y8mRWfy_=O-^m zC-BRL*=&T%6tHO=A8j+d`LWKl>APxjvWMdfzG-j8I`fQ6*E20(&!CZQGU+`HYtQ)8 z^8ANV-*5iKK2c=wtj`<*TLX+s>6-Q&b}~jTejbqn{m2HVZ}p7yQanAWTx=F}Jc^}c z!A_z1E6$nyH#S*t(C2*s{;1EE^V^S)W368ZZwD4wi=$ir@MBj0@{?44;mqCsoV?^; z^H4~T!21CH3CuBB!e2OO*B{wS^-FS|zc%2bmPpgiX6MHVPf7I=F)J~#!jGR7g6;y4 zAhuX#2d5#&8;BBzFgN_3Ouyla4?+~KJkv4y&-5ug1-z8zWLY$m6BVsD?PYc@`NNY3 z(*gY2xxWDK;f-1xtnR(72R3TlgCxc=5f-4OKDVr>I(Qx)KsYpi?uJPoC(x@8Tz?FY zgobgHE;d00vX006Xwx@~D*_`1^kvHR0GaH6C!ga3=sh(xB9_%(PY3ip6;BJyo{GvX z&I5Dm%TJ&mV*)5m$UL`O%1wunp6c!<)sI@`KGIVax%BesuNuBk zJ@woLs=uE3GWFC-C#L>->6_G3)gDDWR7^gbtyObcw^q2NIp4Qk zsAN;8-mF}jZI)$1GWAqXvgPY2ZR7PEZ*$ry-sW9w+F)!3{U=nIQ`=a^c0Ah;uIhDc zcf1V?)p++oh9`N)zAH+yU@k2W)=v=*Wz56<0hG#}pUfeGb|%<}7jRp31#7K+F2|=b zZ#7@Ho3D?XuTT8T+GgdkAddp_SdjUtOhL{sLC!Bh&M!g6SAo3qDI2?&koCD!m)KR? z_oKv~KH>FT!T2L#tVW5Q&*D@49yMRv{#9y^Rh!z1^+vU&ys+b{onNYruTpzwhXB{2 z_Rem6s_k*}wdY@@_E@ziQG2Y~{1jbPJHJ#LU#0f0hT&1v-qYt{Q$j=YI7;klZ1_p| zyBeGP(%9tJ9pai_A`!ky+k1k16p;4>nV*EbC&>9F$oVD6`6bBsDv)i19C_HA_;-wkYG z{Gh5OjG15<-xkKzw=gc>9}8oAH&8{){R*n6$pnWgYL@ShMa}A4{Dbcr>c?V-SZy$f zABzr5FsL7^$JMvcz;^>h)I2P>eJsK;!J&vw)wd{u?*@uG^tghe9x=h7e4-xVyQw8& zVzCMN^RcMO1g|A(;=8W(i7mN`zp7*AgA@-P95Zf2eAS5KQn|qC@p9I+X8EMThEJ$m6?dMI=A1S`nd`;H`*G z)wk$WzCRV6s&91`-*qdWicEhht$Zp9{M;!e;)SMx+4QOC;<^UEMG_QfV57e%gR{_O zONsNp5M88vUQ&oIQobxHhAq;7X%OC!71^JDFptV(-4Cg-)M?@55YCiScv@W4z0eE+ zvtz(xX`-sXj+hfue*#zDsX?(?&L1szWFlOI@S{}ax6N(+=yvt%)5-n`gG|^( z-0Hfg{M=!-#!1KS_!V{S!yUxoI2=4@-1_Ef`yQTu{hrorng3xolWAKYj>rIKL0)D} zPOV}5t_M1ZH++*sA?uFoq&F z!_ETZ(|BtB8rm6x;(Png%sUsY>3Dx{h6d|Mbn7;-U=aXsa8Mdr;otuDnNzhMp)^Ki zWH{S-AKd$6J*-KhcLiX)ER?}pEc{w0M)(~EFpCQw#)lCf7q03#b211`o&BSMi<=B~ zG}Ch&`g;&0n(ongFWBvWB!dK3{P*w>gSx?(0Z8<;iU9q1ShS)UG~fkus=ICM?W*Gh zu#S|~>f+?7M9F?O7+KORLL7ltN3Tv1q-KCq#e<_m1S!Hf8;;{C8lF2S?@)uOWd(XR zP!A1rAVJjatAv&U7gar)MTVKxoWT*_4g!CjJ!x=c#zNrN79U5!=G4$ZRZYfC#?g+d z@8N70$4WjkahpH^C~J1)`2KK$i#J~&T%q6TF2UGOa5vzcElRTG0X$+9p|~C|U( z9MG39k*Z|dR#+d)7vf$=WVq{wi7O3N61OpUq1 zHc^;K3Og7-X_^?n7(qxrcd99DB|KZAp|&%h50-CcZyY#LkAZQV{WD-iS31ejgd>Ld zYjT@kMKZd)qkz?e)0eqTPa5klhH`@0bf(R9ch2eR~_CF{_?epu3=9_V*pt8I^`U!L9 zIcH+rLX6-WIL^XC@Ej315YL6zH1;fI*6ID&!LFG6Op0Z<_gh`1rc)a~h}Wp=`X0`t>|4y3OOg_I&w5PIk3V3BxvB-G5q zIUK^w4Q}2IIYU6@!2|%a=zkPCD!Dwrq&2&F^I50LtqWA~y35_Vw=YxIf!s_jG|%URj1>4JxKE;d9aryolS7k z%8(?^DflUV#I&O5IznK(WE;5in^(*x)S!pv`YB|cq1 ziUEK)NdlE0)bx%=hf}P92MjzM-OBl4dMh}+v}F+BWP(^SgOL*lt{bi=1_sIMr8B|t z4d&kW4y%)3h45f#eB(_IQR8|BeF7U4ypq$Q+hevPCMtyKQi&{tm$t@-FW^kZ2PHTN zP1ln z6mdsm7(DPLnHqS-oN8IRs()D~-ijFWHUH-B%bf|R2KmqhS_8ZZbPR_y#_+N%FEB>{ zuMqoR2LAxJXUmQ7Hp#s^z||Zl85H20GRbG&d|@)86H7-Ad##S}1fM8gMj{9HpUOj2 z2czqTkuwnxBOeE2fMcPGB9ceEBxM}7&HF^jZ_YLy?jbFHHQy*0)c-OMZq0G$C6*!c zh%9Gv(61IaR&i-5`O)?a9VW3-_PP!P+kY9GjIo5h{cq17h(zl_1b>Zmq1zI|fEBgv zIsID@;+BCB_VK``+(M?XOkvBby?Zvd^K!iNlWF`P4eTk-=bFW52`7>?cq=hacKD}@ zrz?rWSpq8YqhK<@oGxxAt9qqVdI}+zOAO3IzS689q9j5G^k`;S)L>W~H#*sW%QY1H|O&c-m^NFMbv-G zO))}knzjk$+yXzt;B<80gZvMuV25nv#Nnid&mA!Ki`Y<5ESf4?wR}`IC#h+jAq$@y zEXYMhM@8H_ya>RzhtCywYdrJ-y@FSTNRA-o-DMWjO8#8A;uT@&;dV|e`gpHt=lbC0 z)xnqMxSl4rB84_!v?#U&{NA7Zgf3}N1Mlas%`&(nWIt|jAi^jVc6>5OIfS8 z2Ic}szU*BB!x6lP`_5VeaZG!j-j%ydmmL42H+8Z8q2GC1#F?^ZhX-SB@K0#YzaiVS zE1xZKE8J%-n!t&RsrkC)8CC>aWt@euFa^4Xe*bRJ*R6J=cjj^hnqe<5?KJgOTDc@^ zu~I?on@|hI^g@e`xL?A62(cT^nZf-Zayp2e7*>ot^Y;{ldW9p;ZJDjR{ zdF2CJkJBA&PI$B>5ND|#!E66B%sswGz zv%xxd7kh8<@&+|8N|(LKF|J$s^zai1+L3U@)Y)0Z`kP9&?U?ryQ)uipay<Qd%9HecYV*0d@Zct#nxPE z^G9iaS4P3#exgi|4$fU-Qju}l`A=6q|1s-Jt{JI+6rOJZ2QZdU3(#U>)zl`5!?=VA!QqpxY-Y!STq7mG(MwPTS`959&0cEwG)`fwGG$ zc19Qc%pQ8#vyF-D>c)|3FIvkv?grZlHJmc6@Zy5{-m{ri)ZxDF<5DSh0ZsspIwQVW zl#9zyqZ($wn>*4yWKdgD_^f}yWgQ(Y;u%lRCWE4MAk=%tKfX%8NLfI8s6wo1n;J|Q z+lKc`6_K0R#QQa7a-!Aya2L1Nv@Yw1lCh0dQLY=o@$qm10^rfKnNOzi3+|Qe7!T8NN9GhnDm`jyeeNA z^a0e>ic0nuOIB^{3a17a7F7pk&V0_849@RsJY|@f0iNp2@61_Q+GCg@(|?s;!-%4@ zwR3dk%M8mUVOyTN5aY&bMB~5uCK%urIJSUkXO9Nbq@QZbChJNUE?ZrnDA?{QdeX7p zKLxz~@m|k*5lGYvhM@r2#MMKBF1EE{>|a_wo8Q%)8Aa#1FjAiV6z0i#vu6OamKsBi z{<=Z4Yw!sUBEZvU8J<2%%QL3Ari_3rEurMhzBQ5Q&KogDzn!kClLlcmk#nclBCIGn zms=|^Jp}mi-t#;PeV(L%+a(WV5X7J7(U)@Rxj5@XKFYu$UbSBpujUCzvTE>GVtGE3 zn+SmqWz_xccyo=DYvybyam$f(DQ5knQ;vQ~o-51`ftS&Gjg|_(TJa_&sy}(J=OZ%IIHJKE4hp7a~u>V zr%~vEG33jbB?t9`iCwqG%bTY=hgz*D6KD4xY6-31MTU{-iv+8ea2ptRHNBV!>z7E9 zfwSseuACuLikHuGQ9=jX&xv2Gb!T|;tLIM=VUZ!)s0-rTH4{ScWUM5E=T z{j3&owjXe%+1joi;(d_=yMB5w+sKVHmfs!V{ncMHq_5nH&^wN}DLH-xA2Ys%Wn=0i zdybI+nz{rb|GMH9?NFD5_eTz%F(;N+ZuPj$YV9HPK7uh47rS8mkD;796loGc!#M=b z{!w|+9LF;|l_X2Ah9`GZP|YlJ6L8ap`j1e%R+(ynb4hx~cGpoSyZcX2`ERH2>HB@@ z4Bf@rOKNtBT@S=RmC|u0$!k84T=ppqAELA)vYe@Td>IqC+O(Z-xA614-_c_6yNNxQ zomjPMlRp`$|H#qH=fYJ^?&h6sf~cJ{8Yg#S`ha!wjDyY@2_HrXNtu}0vh7rqY8sfG z2p!u>_CI!)bES-*nHKW~4hgMUT(U?oN5|E{X^&wgx^Si)MM}>cOG?!eT{z-UNYv#r z!j&UaQ9_!7Uk15aO5IK5+fz{KA9?&)Ivb{yU*d;P`3jw1BN-vzPoz!AMtI5t4wwe1 zpwj6U;tX%oBPcVO#QBFc%F9dcssWqsF6>o^%#1Z-!0_vMFK!eXoF+a&==m{(-W&)wRh)BrkUHt~ z^x*#yl@vXlE1-IH#dkL4IqGH(tvrrm%Xh~0wJvX*f27Bj_})CjSI%)U3vM#=RutwI zC3UZ4S7Q~u;f@DF>@j!RLb4>}T|l@yz*&fjUW>HSRImBVivJq+J3*XlIJ0$B3i(3C zs!%BtE@-eQ9^jc&lOC?-k=UieLP}h;3~H}4cpeypeKZYWMca-dtw6fq zW~n2QAX&Xn(E5#}Ax&rZO$-n|T|6v{XAU(vrrZSFva`mN9mt)A6~IZNq5kyAGaQp|3g8K6IK@bjDRK%$dHkTh;fjH`b_3x8|VFT&n-TJ}K5om()?UV{yuz9`ijX*$Yd(h@_*!%N*Z*!K6jLV#G~sF$VRc>WNI0x#%MBUPTkWPk#09a?Z*i- zT)i|>CIT@?8vq6{W$wrxhz1QSKw<||e#JxduGd+lecx$Ym;qScs#Rkil6tv_I zPH705hFzy={ixa%Y3F5AeFhZ{A)QxdM=+GB7{ED{I6aKB=LWUj>BQEjqVF0HQ|P{dg;@v`s7AkeTOd;^@|7Q ze5VfQ1=Ol$BNtKxs53r%)z&??L^m-_MW49sY&9FVZXUe~PO;Bm2i?~+ciY#lRhu9t zTzcnREkE|&g`|RefLh@D_L&QAnY!`tebD3acZ>=I+sxA%R_bg9F`@Gd4$U&kQOI;p z0&qjr$8GR$wx_`PR8+2)iFm}rA=ZOUnQqzk!UwjUl*ixuaT`ufqO#>rxq=h@au2wo zo<(kLsFy387RM$Ot>bYqVqj$u=LaPcE>}!z_hQ7bvb#kK=#s+qKjnm9moqu3#RWX&g7KsW+QmD7#+s{&?mOK? zN!!BC>|9g$nre-U=cFdfs~a_! zCHVkG+nLQ3@Tlq(RtPZR ze-paVHUHO9jW1yaMdJRVPu7}pEOrs<#qA9@<1!*3m?3U0TxzPCl^6R^>P7hhXutK< zjes4uH{v^mmlj4?zxs5T*^n()7HKI?;o6We5(b)zfTiN(cC$HGU>V=I$v| zVO-%s-6HA?dD|#f+yM?IUPT1I65m+VY|Ris^Sq0TQ8Hty3U|z?X%eh-%2}ZrmT{cw zz~q>gNmv&c<)n%AYG=6|oUnhE*plPe=AW$seUmOnTsSmHxq@J%em({z5<)k^WeH?y zTMe_p796r>3hUC`lPVUg;ww2KUZ)*kUXwvcQH=#6u}1vN9BF6jz#Izxi_A-^Gj}oT zs!Yy}{)zA;4$&EJtlgt!G>5W5v(bQP!o{lb@gZ)-SGx+Qp&iXz6xtACZf3)Iytbft z#P=dfnOGMtE3;Q5`a?mSztMA-f!RUxrn)0$O=Hcfy4mSMJBr@G1$TWS2IkZG2ePdg zm1O|+{z(C`G|?3%vL*v=o|TO6AFSM4{qFID`>RhXt{m9dl_R;TnAnlq%@i;Y8S0ot z(GqR4(53gJ_fo(k$VRiEk{2mYg#5)AF*ISu>!29m-%HB)rnQ!504+p2ekS=YD%w$} zBifk)WArKv>>bgbz?0|^VFBDE6rJK-x1Te``3$L(ygkcWO4{Do#=jM%dm8Q`x=wHx z|4WI!DXP1_)~{Ji&kE$EIV2}kxm)2LG1%f@s+}a>EWs-Sh=F+W)`!GghbGe_>}@bd zjAL7AK_}SD--8*S%8iuRdSsmttSy)5iJ;>X^Njy0AVk5EoFwUHQH zfMgv29jbM5`w3TB-cJwB!YtZ(FWSfHr0~H+JKDj{=VEGOko8QXaD!r6L1OQ@VKUU|5}b0K z(r1PziJ&br%mwib8C{zWxSvoYl}quRc4|qMxjg3zYdy=<7CFDe@9h@C2}3jQ|Ht0j zaJO+B>B4^ny4iP0$r2?w+3c>@vP{dA%|w=bDA`Gt(Ip@fBoUDS1Avwl#sB?2PknXu z%m4%_%JJ?Sonvz_)1Ot<_0`qYE9Px6u&_oaXs+$%r917bmmZ1J4QrX6DBN{4oAaDS z|73D7m>najqxq&%(!xHdV-7bgcIzd8v;q7X)5+|+F>pFOeKnjuJM8WG8zev6ANKBV z+~2t8uW-B9@Mr>$A1_w(m!{Uc<+p3SKHzS3fk+s8Kca;8vc*_vGN*x`@3 zl=H-nnAkvY?sfFzXuSTew{|$0;8M!H4RnlIj*)qYZ*KP7D)vP3RH_t!;3PPGc0S%7 zKT@E{t%MNqx2!;E{MCThU~0A017Ej$K<%l~vy9KW#IS=DaVBzjaOeE2*T=CKhJ`@OdkS@k zmt|UUf>=JbAq+&pbZ2}y(h>or__2L@irnqI0O==e9k5Mh?_3U=t2N^YO@@D@mp|Yf zj8J~?eW$<&^y_m?r1PV4ZzZV({SC0;Fk9yvyC!q}CXaPVmD?zCHrjtJpW`hf1!i%_ zox}z7;&xNi1Y@gb&nDJW*bwa|vFca%#Lw+ZBA@8b7pZPO=-I`9(cBw7D z(|4!6RK#DUQr`^Z0wf;-f2OaxvQrECB9(~S@Vte_^>@AAbLHb@p!y=U!JF)wvx#@0 z0--0lBUIEr25Y`rc#CWeV$o%RC`hFTdM1GvOwK2BbeTqQ2sY%U97vr7m7RJ~g+?jZ z9xM7i&|7A?NdP{+f6M@LoD>+|`3t-`$D`A@0a1y9pMJ+{3c06dK;2#2+p{WrGbpmd zgT1{qdYl@NL2uAwCMUd^55CTWA^k$56X^7_$@vs49deOV`Br6`Km!Qco+4Qlqx1-@$uSkRV zMhHW1`^!cLqk~5b+(Oba)ehU>F=TiWwbQ|ju@D2fd=Lj*$B>IZz-N|6jWVyFPxpV1 zh~va`%6+0bxAV~fKHuH_zZ)+<`j@-7NOiamRurg2*k1XyfnCEHBl#MyHnz9+zTJ8D z;u%xJdB!~TvU5+S$3AdmbWH+)(~HUFE?=per*kKV}*40W{Fp#M3V(n zlZn>Ax81(u`o-X=|8o6!K0o{9?%m=3=>YdN%ccclTGb z;r<=PW?2m&9k4)pH`sk)siJ)cSkGPu{S8zjLT9gYPDZZ?3mo``*~skEMW$2SocdJA7cD9iUSIpaAP&Q? zEc|+Y^^&`ZBlxmO1S3G}GptGOhyU}R|K(rT9E-guceiff?;(+IZrpmf{_p{>8UOR2 z*Kgu3Xt3;!kIK83H}B%A%C&#FkAhI0KEk8i52#XTo zLivOSd}moHaU*|yc6hsI1e*Fcx>keXffd-$^K7ZunepK5*%thDV1TdW5^Jq31K=_i zHl2&47MRu(0>!d@YZZN06~aIc*m%I$9v=4e0Xj042aJp7$c(2&!N(%bE4TIbbQ?T~ zx2B-iRx|!-VPz+M@V1Wn&RF<0H4$slbXnM4n5v7fp!X~cs_Uh7rBj%qPhd|M=(^$! z3jlg&YSMC~l7aVRxvsza35C{fBk14k0r_NxJDW9r4~~zsVsh1M+`rtG0=;i0`^>N7 z%2Pvn?$3XGge%Rarj}#Gz99DVYaad;j#a%CX(r0@Mt+|Vh~}S8-k?=cYf+wm!5-iA zqQ!WVzSb=~533;!ub2|0sq`)lt-KA);%@5TGO8977OpA{a;G8_D~}J0aG4EGapxBQ z2Zdn*Jqt&N)b#3ma@JbbD7StzlncqJU~lZ>In7H8JU*ESX-kPi{%93}drt|USCA_a zktZa*$v(GgZqI^8Hks1MKP9^FsE>4Xh!jguhY2aKT4jGXfh|}uhQHuVs~8k2PNTu% zs2X)KHigkQIFkLKClJEv>{gTCNXPoQqsKyiB)eAaZ*e3Dw?XkNyc0eg9P+AFb_by{ zlT#lHB7X3zU5NJ}f^;faO!ei8^e16eQ22QX@#t`b#S7)_73r_7sM2Qmegqd$W;Hew zuo3^fb~6q18@cT`&}UsY?C<_mwUliG8hV*qU-V zSB4aFM^osS-0Ff5Qh_R5`dIYAa&Vj52r1he;zvn?*I81TuPdeAukmj@e z(mX0C)6G@2r0XP08*p_=@?%z8ONi${kdQAEjnRpBFFHl`KJG_KFV&WM48I z%^V}Qq@1rXq!Yr{1GuB~BD@le0RnoXS9JsZX*vQM#;kbF4^&?ne+&|0_!OC)P0bq6 z<*sC<<)8{6;Bs(2pPbT-4y7J9KVZ0YxzzKE7Sn84>U>PN@npYrywQ8cQN96tMffPb z%iG@RIWA7YY@&2DC%Q;~?^g=;u%+Ys){h4LdN_cg=C^3ItlCYqcw6TGO1;x`8z@!} zJdGOM>%^l)6`?@%`~st=@8euJ9?X45h0*~|4C1oH!QT+>U}uz>Tx4ygeq#8wFj?PU zV81aU)^nNyxPhUe%@Mzd0uLz8gL#6EdP4#Ucp^=~IC}%98znHTbsrKKfoJ%WMBo@a zwC@>e1Y~>9nIXJ<;BY`{lQZOV8U0OLM>DXbjy!mO2x35ov;V?OS^9^`=s<6b;>3t$ zkx(2Lz$E?^cYrIw3u%*}k0|9ZP0f%eRU^nE0IyN}=ro`YzV}?y_Df6{uAQvb9u5H^ zf(%z((Kh#aM{_!V9{1-+;oT7cavoy!)9y3*0Xg}8itz~;H^aLM*5uBJa42GU|Ok2rC!6%o^&fDt3ks$o~pxt$x&WI)@thNfhiue8OTx zs>MFFbN)S>oXH;?(BNPArVr&i(~HRqG5PUCeD}}CTEJWMzx5Cr0|pV~F_^>2CP(+d zT(6kOtC%dsr{q%+=CNSWHu}&xN`NF>aG2Kt40!+R=_cjnACBQF=NG$3TApxDz6cw9 z(aSYh>KOhC{-qIwOXm2<=mh?SQpG>hA(Qv$lUM?LoY8NR+r)`9sXQONmfra{#uYze zaD3xG1QBz+g{2#CvgSo1H$hlqVsHot3WvwsIQ%o4jgEvW^a-h4;_deM53q&H@A!qO z1{L&Q4Z&DsLazWcmge8h6PYU?VgK>%K47LK&L1LHEL3gc9J_qNL0{|}5G}HuDO-X0`Aa0(wciS*gW(CT08F#R z^_I5BC*|Uoc3r+YtU8FWfQ}!90vyjZd14O}>IVDKCvOvEE5LQ~Ee#%?4CYX>S;ZcG zM)C7ZG0NX)-Am$8OV(}4>!>lZh9_^d+T=};FM}C1*A}}rLkLJp&G}2Eu%qeZ{7iwC z)|E&{lML)5|7PLRT>j#4!KozJ30jX&-aL~{8&q6+u@F2Eb(?fa*aw_);FGOy`~eZm zH#~kX*?IIcJaI@lCne<(27)*Z^H33XF+r4;l%n1c4?b>XcKVu1GNQrRA|oC6FdiO3 zSI#Yt=f^mP#BVUwWy1Wc(*?Je9uU7WoZ2e@LkiQ!i=S7r8ptQMMD4-2lkn>~MvU8Pacs`frO;)4?D&G{G)QR57555dT}Jo$UEjw-6wH#)yJdM6eKLea>-KjQqZ{?TFKx3?wz z77XBL0Z05WrYcg|$LDqYZ>1hp>I}Vnw{9V26LuMk*hXq73r=b3H3uRB$gWS%gb?@P zNIH3h6c(HWGRKYPQ1F#h>2Q{}C!k<`fJ&aBybslP=u#nm`1IvP{4iPjV#1a*Nk(qU z#%rHPKa37!M2vl41^$hd2thXUc85Y07R;LnO5f;~q%`1siP{)n@b5NHE%*;pEsC}l z&<_o+D$i*AsDtZ%r5$?U?VH3$A&qh^P1fuLR#7+5ZJR z*h|eo#7}K9)XW2exM)Ot3v9)AX$bZ3ON{nb~NzrFYor>n)J0^}9tYuO6hl za*9Ar203ZH$5aTc!N;aG=$CEmI~}Pk8_k}`J*su1F6C#~8c-q}>0{|gZ}8}kY!6)< zeyXbmFGV2bSwB5z(4-b~r~olDeJ-GDu+GuU={Ps`9NWd!B;X{~rp*w+n^l zM>9r99T*aGW9Br~`ut&yxtaHR_-gRV*@Rmx{3}a>lvG-SzhpR#vi$Lw*I~2m6Z^kl z1e-B@hd;_WKini*Soe$q{cRVF`rYjm}QwIfY8#%Xp%88n$X!5XuezoYCki z1H@0H+p-UuFHZ{TwvD{kRv@ylMZ*{BMk!CN)eNf?4i_!JGz9Vl`#`$Mv4;GhDuFzO zy(~<(jBz%G$>u=(3W?MrUKS!|kwSO;^#YNqGR5;(IH9h#7t&knE9Ub~ZAI=MOcLHPRfFe~vU=x} zMC$X&@18$<%7*5X_R7UO(wu%SD-IsOax z=U^n*`uXs$iCfySt#H zksN`Y9W`#>^$=4BWd_Ng{iFdV8YdUW_%X)*g+wyk@{DE4h0IV3?VS;Id+WRRZ}&dF z-TU>+2!SZ>W<(@=@ISnf;V3t^dURsV*&QPY#)kW?v}WPhzxCq&m+zzX7?NN)e0t~! z-cy+`_wc+Un1k#3wsaHCGT2+zqZN^JJO&Pp3@-uO8NRK0y2pf6D+Qcd9|RS?dke4& zsOPf29gHnY&8oDVUGVZj zCpo-D>iEp?!OrWj2%D^9&op39s$i>oZ_f~cFxh%AL55mj`iN?;&9$qq=+riYxJI7j zvDbC&fL|SRNe3n~%XM7l+s96dx}{_Xrg=xN`rhEV4%#uBnSOD2j=5^JKC&~VgC3b` zKF99W58x-!#OKCGoCTmsG{r$`6Kr@i#(orb@94iNwEnpQ0jc)9t}hQ~AB{nz;7$VI zkxUiKq%&|TC{!C^OjQ&5UW9qW=aa%-j3hv)IxzcQ6$s4BK0B$1|Dp#aD(zaw*qLVZdan;n;02B1dgkhy)E4i_svS%s%u z)xm0*pIBQ@1j;SOjl}gpCpG)D0?^$6-`UJ1H@uUeGAkqIrj+sH zmr-4M)V7;M+KIp~!nL8h-mW>q;c>zZcf?L%!x_72@PVk*q6?%a7oTfP-e??z$1`jP z+3Bk#?STlKTv*7J|=-T${Q+8~K&>T`%kKWPVg>wVrhYbWo7J2*@AszwPq?+qUaOgS9~ z!i79sBMTe0=kYNXIMioMP~XpFyj8l8i6FFqNlEXhf5j4VksMsVYK*uw3L9&hgc`Sn zsd{*SueYYX;H=klxFvZop_qFEo>5ggZ%%-R>iYpTC5oI%9bi)KN>ah(8`1!cU`As&9bmWk*(>?9aS z#}Riffdqs=Uqmbj4uM%rbzCY@PJw1P<~Rf8gTD?0JkxtwoPZ;45QMHHnPJ#ziPnph zD`pc5!L|%tl?!?0Lb;4I6N{|3!bn=na>GUtgOdu%WgeU3tUw$ejn{DXt?gml%5=QC z6;08JcOlkh=U~OAL?d(pKin3OXp?>s^d2Q-tgL7lns51uXwyZ-F@e)8t;cQcK;;7) zBFgG0wGlHXN?VX}MemeLTARJO>9nAMMz2+===|=jpDPBBky8$IUzu+tKNK<16^AD^ zN(ht_lyi7Uq?UP*)F~qYmb%FI5G}V2tyHYN>rq<}ej^Hr=feqwL^r~DSQ3OF zHnkB~l<;_a5CTaz{ryeC~s1yqBkgW3Zb*ULAEg`-q)vU7!6o%n!N=B}h zbka#%)=g@0y@`2WhqTh@bA>XSb=CdJ*;{p)SjG6*QPJtaiptMGRWx4_hZQaF+U09f zX$>fS?if-{N7h?<+3v2;QmZTbl)I5Q*~4=&7SoNE<_zip+KTAk`cb_1ivEVPR9roh zTvJHFB>T#QAhzG7$pF@M_8>Ke6rDFk3P<=oqir&_$!-RcZq~q=%wczwLW>l*%KrdU zhy3220J!=rPEQnY=clxtPcFb?G?Tp}6k=PSRykcIf2!_icq2HwEsfX}A&BSCNnk;Z zadzi>JgwiuPQrAmP0&CV3*Xm%HB=axP<>(YquPf2s6Jzl-9O^7`g9_jrTEG+cW__= z4OIoi+?NUHR3A!7+}^2uA_ZatBrrB$dB8mxSV)|)ZW=`kfV^J&{uEgzvI&MZYlsC0 z#TPpuhAc2TsQ_6N+S}uDb`l_WP|r3`+w)Op2=8`)ovA_$M0gzymDja%*%l&IPE$pd zN(JjNo(|C!+IS^1Q?7Nm6VCx558rKGAVZft_?QCe(=yPC*(oYN5@JnoP%cO$IgG26 z##}10xB+6Bhoz^iT7V9ULlo;sNE^+3DiPs|-)b1zpV*e=&e_>+)O=YH3A=X!!U$Mx z!+*C5nwwP$@wruirXb+R<=~AJ|Gg82bV<=6N3b9Co^1a2pZ31l{C4m0lg+OhQz@|V zrh`4R8RPguYF?n#f{3Zy*W>LcFSd5NyX(Q6MHt8!*)N15s_vr0cX=)x$SZi>Uw7BY zMS~72$GA$!T_-Tj@hmhEy+_66vM3D4TD#=20_G(LPr-I2)sYVKF=>xiGVqFIFV&mo zT`7Z^DPVp+;|?2I$G&S|NV%$+wn;hoQ*W1-8)BLOCF`Xq>=r+=e&~QL^@8XmhM5^*;`}r0b;Yp_Zcax}&wuYjl_=CT)Q! za1gNq2)ajqDG>BRBE~pGs_-j<0B(MyM)Juf-*|>WxE{>oCQz2$NB z%(Y02NqPP?OIrmR>T0xaAT0$*#Ac2wsEiW9ou}Z|#I+LL8|*A-69-*4hIUxW9Q2nm z@5WunmE;$sps1FCa92>d5~#S&x3)Tw6OVV|^7V(k`&2T6OD|{6w+grU3df9PngU~m z7B=McGOB=9!CcFSBqWX~$5Nz|zyrCf;0nz}*9lP#8$uByLypp2>j+cqzyKkOg;1@j z03QW)UR^Ct6s9DbsnJ6vHd$$4j1PKWZ$AHe@4Kg8Zav<9y7i@G6t)0AU`^YKzMBFT zh)G!=H2Q(P+66EVMN^U?pskg5&z8d!C1zmx9a0hEqI zON{or7B`^6#ces&(>lEncSRh+P^#JR!ya{*;(salL_kZ0Y%pvE1y^}O^uy+o|3u5h zDmThuzb&NS?QI?$_#sisy*^0u*ip>qtk+UY0D%%@qA^%=b+KLKAEF3eLuPm>s*U& zbVm+hU8ryuTn0BNT&!CvEmFG!{@y^7t*|da(1i+kGpf zI7b04$Hv{)3rDFj#N0mJiyq-$btF}B9zU7G=1Y2K$b?<1=LfUyC!@X%pKSCMgS&Gl zL|c4xaZ@%aI&}>2d(|-t0h)XZy=vw42Ptyx)QC2t|MxQtg3K`G4@+YP`XIB0_Ak1H ze0&Kng(0jHIazIAjGyaK-k&%REGWF#*8YcT@PSY$Bn^Zb1}b(SO9Y!iSh#z8W=efl z_S`xV06nI)I<8p{zY^R(uri)#%^kO~2p7uEOY7y=&cQ$WsLcj@%BkgI+I&4~;-amc z+j@b5*$cRXvj*FB7Q328ABc9fK3;U__QXKZNUZCQ3YC^0l`2)gqn7FWQ63y|aTiS9 z4H!h>qW*WatTsRt{)ZR>NN{ylnE|w@G%H~7@SY8D*fFR&F}-F8&a#lH>+!|o1nWP| z13xpiqIm!muY$a#?s$j0BfrVo&_`K=Ew_9_^^dSK6);#a@2p*Db8A>b#|XY;7z)-; zzJ*~8z1Wv^42b*Hv99v=`6Bm&&ZVAx3}IzpF0?u@c!8Ef^OtRO zV9GMug*Hd{d!d11YF|QakbooA917nR&BHM8p*-~%>@_Rp?}e=E)5#qRZI#?)YbWq2 zzB1T52|w%39q_vzrTHpg{D1MA3~$+XMFjz=ZuTtr??K-B`dg-r1tL-QXicSq)f z3Da7j+%oqPVuytAuT8bp)-=jQpDzwB0gObrYW&qKdB5mJQ@_aK_!8>{gvpQwI8V4W zW0TS_kwo&9RS%3(!*U!3>8}!PA`KyRfQ{KAO_G_oM9ISDO?5tlK?Dg=E9+M1K5$-6 z6FM}@C!~G?`O>B>@0K3o5JnZlNPe`gt+*Ar8kU718Ixah_JdqzZ*K!7wZ!el9$A6z zGH#P%7m85t3qc@cgNMN+oZ%_}2Nx(1jD74jz?TBIc_n(ig{|3qODuE=HAz!AWCofQ zH?AG-;8`uWCotlWg@GTFw1T!EioVp|cl5bCBlq8lk%LOH&^kVlAo0Zq2*R)qJIZ2E zsVL?WYx-x~FJwgY{_6$2^cU$Uc+LSY*hD0<0nsjg81`gT4bB)2GgJ+ophYHW1-dW0%{wllgk(rgbh|T)1H;2S41I);Vntp(?AQW4cSt=gUoYp#fdZ_Lprv z%ZwMA&RwKfsjy*Nvt-fq+{7@9D=l}ZyL5KMeq9wy)rmvsf$GGUQL82)xg-RsD-$U+ zb0@{L*LroNp}pukN#rYpyve*U%WjLV;s}>EojYN6J;w8;LH7@}oCOe+xsVJ=p7?K;ol?nYRn3xO4)7tUuMp>m(vE(MFo@WPd6pi$b~0@5hBqz$rJ$P`kJNVQRd zwOI(Nt@jA}L`w?&pG{>&3P3ppX`${z7#BE_$NL?Tc|r1R<4gc=oU#H^`i>;kF>514 zPLX9Toowl%hlgSMHd+ZaB_ee#g%r+VJwF@n^9~Xv5T@KI-|FF}=Cm+Ee>e4*%T9_B zjkzzV-P91JJhQd_9*NxD0*x^wP9RIXx?2j zu_`@BQ|4ARr0x;V^m#tr?uswu&{*oKRKye0`Dz<1r-@>_+L^r`oo(}kjhxw(sgaNA zMC3tQk|(xQjXt!r+{!~qy1`o{4WfRg6KjQ8ml*N9TOac?cIhV<+9!kFd*Ju9 z<`wjL|BNhsJut^9V7azp^a-N&VqsK)i`?R@w|4lTD{Khs$(9P)DzIxtehstur# z9-~#oLJ<=;A1l^wHs!ajf(;Si7<-YONqUA5Hd%PFO|ppqKX6CM;f{;KfKAKQfTWR@ zby!RkVPOH$W#=-CX@iOJbfDCelTrG_00_C?z+r;4FTrXXCWmHIMpVp@3B{vACwF}= zjjl^44Tc)aUOtvpuW&X6mXLwa=8tIg@c%(rJ=fxGr${aWB0kCM(GwZ zWYXX8ULAqXx(-t$f7@OZ-9c1?`fL{UryIk+T4gy-=arj+QB^BB*B1bm>LSgc25l*Y+Ilys7Zwoz>`skZ=pq^~_g8?mFSJjX{>TPF-!!kr^M}ef{xoKfe3# z8~5)13YRwBfmD$UWW&FqzRS{EvaZo9&S5-j*A{k6&LuD zk}wJsb@fqF66=l5^w(P2;+8?WO1aY3FOzIxYO8}w)iUrc&1T2VQKesUJ#Ktam4<@N z8%rn~p=IS<2A3ciE*1xL?GjJQDGNp`7D z&`fSz8;hV2yZqI+^zPhumq#RIjQna~cIC{94Be3Y&g})#&2nwZHn_FWojXYrQwJ7^ zMOxm~5-%lB0=3zyWcZl0R4}JtPwByAUZkw*=3Ga(-jo-a!In~OQu9Za%YK1y;(mYs z9Cw8baB+8EZ>z=FKs-=(sju#Pt;)oH1cn9Fc^eTRp41jYu=cw4t`lvK3QojexR{{ z4hgp~)}U;kPy(*Dp;ub=29BIodig}|WlB!)6|!RBO%W}!&pMb)p;tOk<(hNAhF1e? zHYw5DmO~!%{u|?!W>-6E0?;L-~{Gp&-^_W{=uXs-a-&xI)0ylqlOtFQO}jGN+v+j2aSb_z;1#R&-M9T3F~| zW^E3|bqd&#%9&5)KQHlBvKjBn_l zf*{b&?b0&cK5IBjb2vIWmn{pNWMI~v%H_OPT&|s;1y}eYf9slWaHWZ56i+wgpwq<0 z+sAAbWtvN6!8xz1u#I_;ncqn+77-Lh-k1op2-|}5<7*?g z@mX5Pdb@`H{xGvh(F`Yr+;+8km8ekd#)3i7n6&w@xFX?}L>xyw#YLf`pH z5+u9Rw#2!kkLkNwPdd;WprG*nRAqWL9?*w1_9=?;PB{cG+Z(vA`J&6F(oPh3m+9m) zX3EF3awqbls}pds%JHtly1EuC`HW4*;-0IxVAhR%+$8wAsIRb9xW@s^DZ{-C=j(P6 zN{>MRL6)%%{c1En9n4+}q4_iJKgX>wu^x~>?M{!k;%cV$^8RDIf2?<}2ZvaDeW7JTfYbC6C_yG+Mt5uiC3Dg#x((bHrDR&}5E+9>^Ulx!g;_ zdn(gBVr4h>o1~ICOrm)Al8*b_urZ+s#*InmINEzkv&hUroh=Ma#&V>EN_nHKw~{2I zna}`klQ5F`*WRNi&z^4WeYv%zd0`vHNg7z{&Em))`$F=%HjDERL%aC%KYjDXvnS7` zMiNToNM%N8^pqY`#YU}X*FzN-d8GMD`? z)i4d_xs4cZTbbkp<^x8EKqq)HICAfTvtDJuqZxSu3Q1AiU4dUH%nf>bb2J>|MIs6v zc_UzC!3@Za7}PPGI!)Mw1BeM@+OT!2WK$0X>cq_60Pr$!ZkuS)w)fERz@l6v5?8`X zH$klLeuAA*od*RKbr2tCrh4bR~hjD+5vvbB4&cv{mB#nJ)6L+ z!Df<7&KbBJt^frvn>>zL=+P_*s4L5fD@Hy;zFOFyL?|~_E|+Oa_Blk01-Z@`XE0(&Db-RQ^AVCnOag9goZXD|jXN;X-nJ5n zDPY$^A<1pirFLMAEAsQ*OBa~Ua6aMU(HVR*a;;Wa&N6je+I|iLx~S1cTV1zkncb{1 z>?d>9i>YC38(O)U3ji_hq#yCpZwdCH2MmJ%a2=945{t5uET;CiNSq3`FT?8}RXeq0 zo2ENeiwiE3GfCG=1T7h$gGhBY6&+d;L9uo8ViNujcf%|FM!QQhl&prd7ZXPtHeo=a z2#1hP`a-5v{@~RSXV~Hh>=87-aI5&4?GWlDuLIp-t?rnQqaS(5`#PXLWUNxHZzW59 z!a}9XC}1ICYLZaz8hD2Qv>B*Jc4WXY7g`rR+-PhWhY0qnJ%ye%RRqDZooi$HJ~H3D zuIwuuu<-Ro?kHDl@`KYlT55QAY?0w zn70LU1>S~3g^Zq{eufBAIOMrWsBA9Q3w8N^EDlgQ@C|RYF#0~%e4(l+_4y*7Vc}G) zDT~3`23MqvC)iYYB-HElQ}4|HF>G9R<{bmSJRO}NYuFIvjlt#Ey^`r^4I-?sK1TmQZa=NQ-=5$;G;0EZQ9Iy`fyR%s^&(zWz(4rTCGZa}{+ zlVrf;QBHtBI%BXjW-NfafsGai+*-A==Eu{?8_8$D*y*k56#M9pzkB*q~1lBt~h!p__EJ^@@nz#ZMf$0aur4+3!q|zV}=wn7B zd;)zef+|BF|w`d86nwx!$O;Bl=XMx!SwCA6HGDzV{LOholr)f z3xN5D(fl~nFcd4`tOZl_A&v`nQ~{-jy@uvt$7*V+e>vn?j?f827IkY^Y>@^?n=r#A zrHFOzj3`M>xfiQ>QyQ)&lWoL>w+P8xoX%`}t|AoPyw$or%(o1a6UMP)A|H@-TCtg+ zlY}Db3EDS(sz^6o+&P|gAPB}mBylZ17S!^ARp8d6tBRs++d|b}O4JGEJ*ok`z%7+- zLryX4ws^}ywO}Hjf$rvqB zt6;U1i4nO5)h}ZyN~H-FiUgXE^p9Yk@OUT}<;Dc8Z!z_6NDbx&g47$6zVi#mrsO>!#LfCUxTnS5z zd3w=2S_VNlGmVQc9U@?S|FsLGTRq)9=&Pk~JoHwVTDC>-R`IdXX5xfgaLUuL+>)7z zn281T(& zH&ndrnOm--neJ?Qf$q&qN28Z2dQ#f^U{}q(TQUh(H7S*~XXi;eI{ZKQh-htTIfoJz z57)7NsZGHzR3r$ml64JAHYbkG2h$R5_C70+9mP@(le|0nh-Kr*5~W+aqPx0wv3)X~ zKe(r6y!^nf%WTx`(~4TSv-?4|YqdIW^6sdtpl;jzcBm=_*R>WOV=BH51*x)GhnvEY z{@@_7dJ@P*t4(JIAv4)V0MHRa5adna>0BLJsCoO2SG}VTpLt)J{nO$*dmnK#YC10s z2DK3~u)X9@USTxB_|hAs4QA6o{Bewva}8?dC|RdDM!rMtT&*6Z8$xHrKd?sI;@noy=0)hJ*p>I=F=1JUYRuD$8t!U`4pwewh|a=r~tY z)Hd6v>gjyIng$FY{B+qlD_O8+Q1o(&SGqau8q_Y5Xux5yrk2((S@??fa3Rv`;^7)h zsq|Gv#A8H~Lxu4p2+zc+xp5ADbR>WsFNj?>WD3rN9`p$cj5Qa`FIc+s*aK`M9!njl zg(IqSQ{5SdyHUQitA>uh8^C{{VFVaB<9d`$uWUw}URIigloxos#4f!;hPs$~Wc2XA zm=FEv9vg%-9*X-mrfHDj)$Rxze6agc$HovLvABg`&GJ`Q7O6z0}AM z6zUmPs{0H{t)bP$P<076l`^h!FMmG)N7b=LD2LIzvacEB>?J}u*dVzQqxJwEXDHe? z@~%z`)X2_NQ7WOH&SG57S?Rq%Sj!+-;HT?1HWVAn;*PwBunI&9bHhkSQ77 zL1@Kk28X3w=BS{n)vnIeF4jmZt&0KANT^Uu-~^cx$cZOV&tO8}VR|quc?zP~KT#Lt z+(up7=}G)u)x`;yGn~~QLUnekRALkYx5p2@%t8zBF=t3?T%hB|!~~?r=Ie^?1Qx4AIUNndPF4GNyNvd29TLi)|Yf7OxI0Mv^3v zRrcjZULQ+KGP_2lPP^2>7bulcwDBoM5rO`$J%+3N#uu-d`fGCH`IEE-`dP zi4M>G6&5LEbvFY=Alravp40$}xxXjs7NoEh*#DhY*Z4@!N(;~B5o9V5#6_S|6^s~A z!eGNI4lQ+Z@&i=8+R*C4-dBx-#0d*B2520(Px@O72Wgz=$2nPo0R){CtLa|lybaeK ztF}X3%o}BFEIF>#2J4Khu)+~jIiLJ~_*RCdAr|mk-Sq2?g?E#M2R$L3E3yrIM4zz=0G)u{C#xemZF`&&?CTuEhSxh*<{la>0olgkO-t$ zVF5}%S{sXP!P>Di9>My2_V8!xkuU-#ttqaRF!#N%)h=u;xStH#KZ8WA>L+S%SEg<1 z&ntL?mu8NjHk{-t+!33?C$D(6T70vw&X0~@){TD{O($b!Yb}1Di;1gyYoke33IOaa zIAhGRsXw34HXk2xj29s&PNXFy(7+eY=)qR$Td)c*kT%YMfY?MsyEx^;oi;p$LjjPk z`3BYbb;h{CWwp>p-y z4&6w$&E3FQI1N#J0zo&GC9Y2jeXR0!rJ#*)U^;Q6gA7u?58qo4$>0#`gLrC$@xnjC ze)=w?8c`21vd+aG*NI6RiDYy@Dr>RjBcHF12;=}S3ombp9587B1?gp$o6=U}G`i~-k53D}fihJT5X>fB4>u*>j)y7W6BPbdOUCBUxf0qTM|0y;BiZNuDVl2iwP zua%-*OX;Dv_d?8~oLv9^L`_P=1@x|h98yqWc#4)Q3#q-0(HLpFj~M8GU5v|jY4op9 zy*+jizAYB7qnoPKQuN8Rccha%>ImNVTHLW^9sXTVVC?Fq*-cb#;6iN&_9(6rPv z3pV79*BMX{pv^pfKMcPa;eawX$!!B4a?Xl;>Lmt0<`P$2hRx6_NfwOrJ5)XUI7m{5 z{Dn3GcbU70ft@(hfe=GxwvIrobkT{ZhH@mRd1fOTU8p|`_q1&Ien<%W>Yc5H3@i%t z|D3}dvty)nF(b1Gr7lL!$P8rS5j^S69K?XT=#~ax#c>T)1SDF_68HPr4IVduE+#1R zcP`;Y8w)d3v5GvjW{Xy(Ah$JS0$z44xS-Uw#lA;{su?+nz_SHH2J2C%P7{XB-{@?6 zj7)Y&SzR>~MuKeNyW-~-^ZZx_(Fm!haUmm*8SJ8aDOpTn-4OKmVhY=SPU7GMTh$WJ zjmV1&j*TRfyN6w&GReXxq!|ZoDdTd0T`LUB;4z;Y3IE_Oab!idTMfZrNB2LLEzaBr zkCEVY9lC}TS^4Nk28YzG0@vCefiz7iUI2cNkal!s&&Zwo6@F*KAZiR+E=9WkwZQYT*h3LX5Mra7xVz79GvBrgPB@kVFA2nD ztKG$%wu&>dSIijx%rXIJpQ1F{BXm>iBMPJ(S{qxk?a<|a7pb@(e+B{TUflAg$ zQd^0RZNo6{GddJKdIcs<_{d8zd3RoL2bwWgOJt&hDoZ2wIKnlR2KQd1jA zEoH2+r&~SMydgmRMl%26e?cJ&qU9XhIfLu`EniG(3mlJE@mLiPBK?Lz_qaPk_^>N;okyg$d1qsFLt|kD22Rgd z$eSWvxq?bZ4)ayc<3|@Y3AlKfuLw<8pqintEP1~MaDv=R$Ym)RFNz)akAt?V)OuIn zWgHkxB`fGAZF_c9VCFVkNa-{qJZ%9mP(Rd-RGF~LQaHY}T$uw5OvPnp7?6a|ZpoZQ-M?aO3o z@PEt3E!0~V2+>m~W2*dbXxNco38P%@R&6yVRzd5=y7OJ!0`TmcZ#Q?g_VB+K+nY}$Q-6)WpvON5W#x{Yv$61ZKGoQ=9zx3?#p(O|Hz_ys#-XnU;<1GZAgxsOm8ByCMhm zp97lTjjcVOm)G{?y&;T!{id#Q;J#XZ#202#wUQ@>Rygq72!B@tUzs?AJcE2lr_r|% zN&012hAZC19{?!S?|KkNAEXfvwxo?&RA4h@Y{61oX^mMEG6mop0KMXpG2+Isb@9|k zk`_nH!p}a#{^Bp*K0Y0sUCMNbTzd&)2J8jiAC0?oTN)}jx>Q+UgmD$X;%3+a+8j{k z?&lN{5elZUzZLROgWy3j4Sls4G||#mm!~sU)s2dxTx=Voie`kf|D<2xei%sibri29 zw?~`-O-a*&c|IG?;KdDJleMd8M*M2n>^r_oL3xTWoqUTnbVHrWCCLkz4cD(H!4`lK zB$>-30;KeSdmlmYq%O3;vc4Oig2ljwg?TfuWfjg`FifN~UGB0YYY=Y#K!{ z&i75>EQ9L^gMcq-kY{Ln-o~Q1nmE4oY9INtC>A03YH$FVH#%)*v9M_@5qb;UyzjZcWFeBVBk!y6GU4glGo7U?5APf& zraV3qG3{T)i24Rs)eR5qRYl#M*b1z0;b5NU-KMjwm_;A1s`Qz)! zZ2ky|-eP%K57x{E?x~os<5-6*3?Gpdz7ooJhDTdJ{_<5yTvU(r2$vH3Ix|OPpxFSr zK(QomXl*NM=kKXsKF_Bpf0-MK4DYxUh%u*2!ndWkqs#XMY;kcE#`Oz@FRvD`3|5zd zbD84h!0oIJ5^|x)nC-TffCuGWg}+$D>?K1JG|BY?*t-Wf zHHU~_O^zgNQ@r962~6T+N;#OUA6?`yE1c!lSN6C;7d1MgP;BfikR!9tmy_|@97+)# z{P2qO`h?-+uy10X+Ux*3MbiZ^M3oRPh3kkdG_6?1( z;p|(x>s-qrRNd^@-TSpw@`>nsR>>M|57PQ}%eXFg1;U3J5LpuZCM#s6#UY9rwtsLK zdcX(_*t0Wi5RGSL=lf#SN)?o!%;0GF6Pi(Cu@KA=uw&LWiB^WtKGo~=*cq_%dtOYX z$V-ZlsZK!2d_q)viBu#sTa9ne?XSF`a{y>Up(JiI`V zus{5TsoGmZs(c)wJ>SQYuBnm(X96+}$Yr${Z&J!*u^1t}Z+tEK!S#3$Xw`wO|1A_0 z2jUXSYW2Gdr3TtUK&6>LN#KE0G9r_JjG*q_qD{9QXmmA*&3R6f+*)++mM4jb+%*#s zWh-{0bObOXZd^o-jlcsR)Xz(IC;wYdH=hh8ulxHQZGN)a(dJKe>%@ri3ep4K?4rwF zpC?*m!1bo(cTK8}Ht<+qUZt@{C#QZ~1UMh~bb5K&>m$>xASA-FmAGdL| zC`8Oi10p3js5Hk^Cjzq6MQF~SAO|H7?5u)Hvs@`!s;8tqqCJ^!s}x9s^u@kw{z_&_ zbkM3U(ym>2UXe)GBz?r+J!~m3dJE|XyNXkw)Vb%N(^{y`lVoNq-@xgrpgI>55=bdB z^DosW4qH{q@@MNZPKv82>?g}01MZXW#|NmT^pa;!tf5GX3@vx&BZ-2dtx(!zRVuYr zThMI_+MV{S#Y6Wlb%-e|qF*4Y{4PcY$EiE?8*0_2w-v{0be_6>AGTI$?oI8+$;*7f zm$4Z=`-z+icmds39_-}7nOO?7!+_IZD6vTfXQlgrg^#JR)3NvUA?Oea0uzsFY9>J5 zW}j$=q&AxU-m*7|*6K-D6X8U~RFiB)g1Hw_TS*FaGj)9>665LteSL4+Apmqx6OmB} zCWWZ$~xq#Yz7I^voe*QB4pWb5u45yNXp+0@D zCOk}x(HWct%9ctvp3P~AultB$QK4C+B~$rY-_{b9f7+`y8%&b zcAxXSJuLE+nyJed^bIQpJ!|u_U<3|%2N`cW;+qwsiSc$U()Ow&XMT+2r`}(1cwZ5s z6jV(quTTI5(KmOQR*H7vBI5vL>QzXk4+mCHhCvkW0!K_P+01s6(!0EB$weT}or{#s z!dyrW{>H}o`fPAWpM9VQ<4WA@c2D+2KkBU^kjoYWhF$F}){WPv*z-3+w~Q_`tqKVQ zT`3kUJ;9)Y0x}55UF`yCnR%Yd?P#j7pi~{V!eYMQg#NYD+*lqVE*)PfKKzvH;sb?- zOWW@m82(}Splcfdys%CFHC;nk4iya~eLZ*3XCagsH%VWc< z@S*@x7cVN>ctdCDWF&e0JKu$M=4G9c2-B&`QVdAYsj%A(DnwqNYt_q=r$`B$@-HL1 zh$ncB#8Xt&ix-tAEODbQmWm`2g`GlH2@?|DZcmqCq2270picMOmH}lh+5n4}ui&B$ z!7dlKp4#UD*UG8KT`xv=qafnESp%k71bi>9^Fns%awQ8B*ZT6g(Qg{~MXX;XG)E(` z1u{T+l6I@9s(aC#6QM0PrFqq%BQMB+vM5M_KjPBXnlXtDZ^x^nX+C#L@v&9w`x~I4u_jcO64eZd}shX_3Oy1aObq?N3y-pQi7OI@|dDZ)o_|iqQE$P zS7=*j;?;TTn({t`-{jUQ$AH) z8tDGtrS5@IL4t^h5G38oVMxDFRx>XLaV)f262zpl-L(VUj5;5#y^Jnh&rGy>IrSC5 z)77wg*!y_S$n0t>Z2#&>SA}~q+XZ%DMTycUC~eK%Q#+~WO50dUhr!D|RJ%8p>X*vj zr1FKg2>zv=wC{@9L_ONg(tYuEb=jX!kyTuZ0pW?xC<`O}SiYMlGVn+Owb0>I&s{K4 zEC_ncEA+;^TMr%agAzNI*Ngt^SmvqU+feZ_7{&`(r> zt|er^jhT4q?(vc(Z3Y_I^^g%bx#>IjZalzs$xxHGJ@5uQqUgazC%cXv8*w%?HhpIUIo$gP08fmvf7%v9{17TGk`I$&Kql^cDC# z=Mck4OHs9t_F7cQ+2GqGC>9S-yNM`{nr z;0Te-sjqLx+F`0Q7V-NbaAHSVeHvA%PN_v ztBD)abJi`z(p<@Jg~vhnbq3dc-HJs4X4V_ZO+46w(3WfsbaJ!hepBDNbKNxZ=t%Ai zflg4z#r#SY756Q&wh*5@n0L`>uDz3~Gg`Vsj%0X8T`)K z4hNvB*mpR!Py>G9!ipsl57)C+kU#oha@uWAY7bZqA?6QHCJ2ZbAKf{d;5H1qcH=VZ z!rg!;lQ)(bTAyAailppQhg|pK=ZIyU%7W0RX7M0@udtJRg*rtWYzX}>`MV>)SeGH) z?nzf^9T>oMz#rK;+Q%moM3-nhy;Z;2yVYCQao*{9>H8sofIx-k>b_gdfH6;!rf_dV ze))Z`*`XU~dJo600}!rjc-+W>^vSem={sQ9!qW;D%ryMLvpFuBVmBiE$lH)%AB-1g z*2s_#hW?|=`46Brki<5yc9{(&Q_7IY0KMqoZS7Yd8TbJIrxeK|02=8=4)8QG;fw|4-hr`~3?A>J4zee|}2yj<|y)CAC-P6#OBS9>qQ;2Ud zS6ESW32ivF5p?HWSA-`$LiK1=>!dp=3qs&<+j|>91Z!)74%yMr3ZxzGRovHy&wAf% z{&Da5=Hsos?WZrczS`PJR2%-<3Vlic!;amPAucr-VAaflKpZ#6mLg7{Y82(Gx4jv1 zn+aG4Cr1-FagR?Wa&yo-g!~4JuR+~B&WS4>-i%(4aIRrAkn^1Ubr)yvQ!jh3-tI*& zJbl!8u=8M&0Dw>B3Lc<>16RlxF~3SWJ5u=oJ!-jK!Qeh#h*$>5H2 zynyZ;{;w(05)$?ENm?BZDZwb!>HGm(F^%&M(&H5AbT*ldB;BWrsjBJJZmha8#=P#Z zxxbogX9pdub2#Mk7+S)v;fIIv?J~}FSP|1^4Vd+IFdK}UE%hY4^6Chk4NejJTpSFc z4J`M~thTMEjduaEu`vq;0s5pHD^a0~aUsPV2AmECwSg#lwUtu~I~Vsgb_MF!`8*%} zEoDkqn){HOqb(>l$h;{?%u%H~paQJ`X!4YID=rBOML}PT27)5Nwk<~l72tGjGz3?4 z%0EV!(#i1o@Z`{qN=ouaCzt_uyYKPB2AIdTlHW%$#v;26!FOzh*sciJ(jvoLz`OdT z=@?Q%k|DS|l}~5U!kAVJ^cUwgv}BR7sq0{MK5J)meVuawTqjk)Fx7Ip8D@I|ITkc6 zS5YWD9gO?3)A!IEw8@~D&{BlfOr-LC46LEEm_{p{#j zB%=zH&8{F?`p9u6Mq%HKg=@l(&z?9s7~(q7p>N_YMU{>$AQl_WsRjYRoJLGIq8Y29>ZS|sGXZK(o?h)OwOI5W`5r5 zGC7yjg0JpD)^xQxJ$P=frpm!FJCG*Bqi3lv%@soGL>Zyxinkc2;*LysTSbY=<4&pw zMZL7i@Yd9%WHE=s8178{{F!?TA0iAE;@W(NADOuv967`$!SX{uHefrK1CD%UqV&7G-%GUF}x=?6c1>xoE*A^ck-9We~5k1VYgqM1KFWc2R1Y z(zsMb)Fy1>7!VM^he9KL7yT_JW4u!<+eojn!X~F_fn8tBnb7cRo(0 zNjaQMn_7@2CH4w-JRl>IV-Ln}-C+TL)NDrQE#znE5xLU#U%Mo^Orq51fNx@kFr_>w zF0GwHNQt_r3tgBD#r7MEJV>pE_fj@NH4@K5!`k(N*uzr0QPCDu*h1Dud^hSMS0X=# zSc@JXyIUG|{lvF(%|#i^9s7WA>Yg%-`74~xpTea)98C9*6L+MKv0T(cOv-$F@Wf+5 zqG(^FR6p88VAJ`@0k2X*DtY9QfCY%%&53hc{Lmn7HhhYsL%57+jP0eFgox{>VC2#0 za<5yKLOIZ!T`bIJ-|a;hayHP|V+bL>g5-CBv9GcJ1+%5>k0}t`I_fDag9 z!UO@#tJJ8LM|hk|#htXr+6`eEC=JL4d@2w}H=P1a0`Y}PT&xKKZ-f2%v=ZTSIbqio zth5eE;0&F=#>HmX)Iw3*Dw-TpX%$k`%q1+LsAmx6JAL-pFZe) zz4_$v9ye1qcXl@awD)A|=~pklPQ&cEbDsnFRH{{9)t)~^#>)qgo+$H?m7#R1y%w}E zQ;d;H5Y(jHFnF_wWV4KNjE-QUd`<(0$ezDFeKk1&ud>Us@j6#!bwrIixFI*AXb+Q> z+0#Lg-rCD{;DjQFGlRjN7!P<%XQYH74i)OcWqctPgL|<~l#b6z!fIz0qC%*!fGk{G zZf;ftX05#+mt(A@?cz819KOWTP%fpCZB|aNXm)|Vz*?Ib;@bL}*!X7g_19=6o5D)bcNe_8Uh3<^`Gl zr9wad_wmX$SsOqqvM$!O@v?xM#U+C7eW6{Fvr_NReAN{w@)9x!rfq);?xr1+AIVck zF|sKy$7oXWt#&bGVJH~fOxnxlz4iMYL>v7U zRR#ai)j=EHUYe?+Lr}#Ipe*R_5OMIQJrQx8#0!EFWDYT|;N>ACD4M0!KxU)uXt!>O z@-9m<@5(@2wA^-2gy`y>RETSLdLxjutV@OQ)jKV{bj({nS{L0AjzKa!M1CwEQ8NQU zmqZW5B!sW7PvmjdG^Xt~V6{lu=o(n3q7lkNJeU??@mZtsI_uq*z!}x`wx52v^+(6* zl@*5X#-qPBv<1FO$2DyFw|duXxM$-;82D1Fq=?^LXJ_i@@?W7>Fov^z_Cmo4yJAyg zrgxHA!FY^=bB3aGOX6^f)b1)#eCmts1;WbpIv+`*4YF=ES{6s(Efiibjl~=Rx2$ap zwVCm{N^H7{8;IjEQKVD6?xO_cmp63ASjsnse+^X~AuKq;(bUs9AUj>*Y&|VK_b$M) zR8V~M5u*W%Fy+~IDgg2(Rg6^>54M~tcf%DH&3y9o{PY!X@K*KNg94Em{v0<9>`$gs z9N~4k!EauFFoUy5?(bD!!tLJi@W%mSPDiJM6Q11eP4?%56N~=Rxs+gvXltPk+-DE@`b-H(#Iv!Qk0UtsoYS`1+})z}IYk#-tNRafn&n@QEvK5==Hs<8oi1~hN7RGjAqAy6X{L@XNIR|b9jkltET`x3SJ-bw2OMXMc-Y3 zJe^q!d5EUm`f)Vx!M}C#R>CB05@g2%y9~qpVT18LeK>RQG#GiO2)!KtFq%%rjH8Z8 zcawuQS|{u`q-C5z9m-VY8I`0+%{v--TO31%kxON3v2h3^=J76RLyvd)F62##n`_hE ziZnYDzlS#lrd7Yt15i3iaI+Lc8_*!548E@;lp(nS5R1!B-O~58c2C?#>-P~VYK`OV zo$aTOx1Vmm_!EN|*6yH;-+5-!yTZCTuT_Ts*{Xs?Qzeaqq6rbC*LO^lzR)Xa9bNiH zbrLUI+6#3L9DX=CN5)0SQX%?n`(4>zv6Hn>K}iXi8e8NpxJ5^)S~X!GayYN{0_KYE zr*4{x|DuWT7;1a5MshBj8n)V=Z0>xuWzN&*+yA{)b*#z>w;Nrx!-}B@z>1MjIL48v z_E(mnTB5KLs-|Lj;=_x{CUsC8c%0{IvDDGR;$&-S#{2Ng4Zj}DVxrg{)l;%0Ee!1u z3&huGzj;o~Dy2C}Xj7m_JSl}QPjJX|`ibN17ol|ua|4=0+0=zfOHyCc<%3P+hxRk) zNK#w{v|&EG5-Q$y|Ixst>#VMv6Mhy67{DgX3^e>KMH}Z2S%l()-*=-B^jnN~LC>rL zL5H((xX4uSP<5DuCrbvx`9lPix#k-4QL@q7OQPed;i@I23oWivC6!GjW3|B^P@pkl_^HmKmGb7Ih+LAc zT;2<-3JV-k7^-F!GF(`w;mqKLRV1t$d_c!+$%J+_MwVf^64iP0rUyO%`HG-bWAyem z&d(4Uc&XD6&)O;Aua4jWcTf&3j6g3Zpw_OVN{DW0G+JU>2RWc7Fnw?i9iLd&GM3wY zS!4gu2=ea)0~JN^OfAteT@XfYbYgL!-Bs85wUrMAXJ|_NvJ>8A$p+D*$CHCu?_~5E z(UW@{2Uwc*q7O%SNlib#u}24-Did{(j8S1Q zo88guOU%8*3J?-!3>AnIDF{-S4{^0IiG0BAL{jEyn;1)*ALfYer9$Hbb?y`lSm7j= zOn327-4zsW3C@2YM~&sMFSHt~^$AY+LJl|7GD+#-CB-dw=MI$DcBok1hmRrKev#Be z>Oc8wr)p@62jPcut26X5_%)EvbEsf7BD(IRRV=LPgS_O%JqqXqZ>G3?y)a~Pv$-}7 zE7wg2ytL!1uHyciDX+eoe$QxM_Xa9w(YP*ET0pt6hRumWDjq;n$1|C-$aW_rtb8nq4`V)rLkbxVYQ!O~egl4LUB^2$g z=Ak-|u}QPhOhf~TX#>~3O=;8qQnqMJ6$KPvGdaP)Ma(R0(V_Vc4$htAuD9Av$<(EL z{2?L9-8we3q)t}86`5CPwA4clljKEofB}+E27h~NO{Zp((W_N9q^)%)v80h3YQ(bM z8B*k~+pzSMCJ#zjzgTbr!$wDPS&)9&IK)AN4LR>>t!&JX={dtWZRz3L^V#t_edsu5 zjCE|a5Oy((Q*js@H|$x$ha1a#MRlkt*M6K#`=H#m;0lrpi?ihXLXz%dM9?t<+8ILM z5R5G|kX1sXS$wU{(6wlAAq_iKY7;N8IHcLm)`FCaz`NR(Q%mdGrRDQM{73;Lp}26x zc3uqoM`RMw*{_uItCmW$rlHFPVnse}oNPBDx38KetoW~HxHFBhTxIQ?JaRUDgi$(@-t9!QV?Ndfa^i82PU(niB06DRvcxNbM z_kt-tJU$uB=flE|?n9z3>t+GpfOKMO-AMxfHab(o$R(+sn48&VSnqsBsoB@JT$jb< zTzT=+ifv?y?Mhc0%YRchigiVarWpRzTS1@WrZ|Xf)3vr?4;~Ra3mmn zQbyXBJ+pC7Hv^T!fI*JtYqQ=M$0lW z7l!y1=b>3_^8&ja*`SR9Kd5D;pI{?cgI# zuAp~(HhRE`aCyUH;kw)XVj?5)L#9Rs&TKk~f3w%8l-$7?3b=z#MuV9Jn(Tvj;OGc4 z7o80DVc<#hbXpn6dIb0I`N=S_YDFc-+1bhY5%@$vEef?YW)fxZos+K5oM*k6LnnRF zbTZVXoot2s!2o@GLE0UK@zNB?-eio}@Jx|KnjnB67aUf=lujwzDvy*i3%w|3?x`Oq z7Q}FPFf921mjK1)E-dhJacdrHqsRLQEq&@Zn`xbRja{4^yq<%dvWR5rO>jDx1*Vll zMMl|mq%$-FU5ENJRtir$>iNnl);asBP$Y`mYFoddK*0ta8^FG-HcO!)-C#)()r&@G z?JZbQvk@}@^~_;|2AKs?d=Ez_lUE45+U@V3ApGS85~{(++JCuzJfEM>I^Gru5UV1P04%m$nw;8e)KgHX5_;Kd6_uLb+5 zr!@r}_9(N>(kU2D@$JIBI2AfXMIHdG4e4*BZEW0ij5YZTG$qMW5Zv7cY(I@-ZOT!haTovV)XI#V@p_O1w zVVf92=zJeBD_$TFi?pyhedfeAz1Yzo<6lAZZPP?wR_hm+rVC-LTFuz2{tyaL4xmG( zh*^m5s+A6;=Z2P}KDDI25*<#$Gts9Y!uliJrEx8`k%6Dzzj`|#J{gXW@+I4>`yEbu z{)hDG*pS>JjZdki* zWbd*Ar_u3pgnnrgUH4IUtY@OssEnt3xUjL(gxUl*iri>nL(9^K<&D}a!$K@2;xUS3 z+RzqmmyaZnXNQLf8fd(%sisrVJ?dDF)8P@aV_pTjT2pXqkIPox5(H`O<=EL79wEIZ zXrH59w#clp3`2Y6x4Ta1uR5A-Ah-FxH<)=FJ=_~PN0-%)S54$yi4V>p#rqoL*>C!7 zE|!uGO>IDMV2=}t9_U(Q$_5sAk4)%QjV#B=b3Lf5H4;XQ+vxl6x%c(#5Q{`dyk5Pw ztp3svwhNgn>$2>Lw#b33y{nLLsVyLspQcWB(DH|5QmO0ZV1E%4mIL8B_p7t20)fP= zS}&UvPj;0G<;CU^Q2z7p_ZkROhAT9pCu0zLCa@; zU~>>gJ1vb<``Pq4hyQ{DOACW^efE^a!$VrBn0`!FPjYJG z3yyJ0%W+&1nolV$PhIUQD?!=D*$$AMVGNW)e{EE~2|;BiSbuB8_YTMFi3 zm(udo7`7B|4_k_oqRX&}jrIEUV?ORESq}te)*1|4h1h3~y1)Ouw8jk@B6r*JB(S=S z#c}Ds%T(}YareA!xT|#mnYXpD?T*?vWN??Lp%r4d6{UuHl(RFqzX^~~*h-H+U~R6z zvI%R2?WYT2n-PooH)kWiW3UBzUEOy;M_Tu?%iHd#t#e7Rtw+Yk=ATOAfI0 z0VZaYcuP`Kz~6)Pd73E#A4^DAl-fofGQH3eZvPo$SLMb91h-%}3rk*_heHB!F`DF} zOJww(vFA6VS>*4-F;=^|0S;AV)EMob{|`<>?Em@y2&?8}2p)Wb9I`J(A{9O#14c7) z{BMRl@glW!gu(HnVB669;L6jopH4xdyM?XL0d)1KTqLUXFBA}m@%8b@q#rrFp#SIfv0 z$Y!;@1_$8>g(Up3c>;}c!N)60iA^Vt!yh8!g`~Va8%`*oEM+XorieRkq-#0O#)ZkP zu{#V4tgb%_h87Pv9{6~~`>n9d`(i@;id5W(g?~g&0i5=J_Z;qK?290>4rh7~uou8D zn+FqYv@o2C>Kl*lI(pEiL?`VJ&Y8V!1S6dq6?P<$&WqW)_D9qG^HcCP1Z`l`9V-V5 zlJAOSJ4`z3z z?-_W`@GdV|ynFxS-~4-Om5a6WR*Ji}#(KQ?;sqkbz)xorfPzPu>Eg}I8MFHSKZIq= zxC~&ilhnLB1JIpq>>uMQoYDEIT%K`u_lN(uJDSbThqJrLmo^xkJRBW7_|JR7OghJB z6krQfN$`%!^bPrC^wKG!t2tH}}S&}+gXq8UTqX#AO+tdgbyNn`W~H6 zrx4mD%G;0tvyK#s4FxR_I~Hk3N(pGtCb*Lv`Lt34(As7vkh%m4Ag~Ge!nJz@ocio= zF5l6NBVjtK#OuhuSYbON!kkFRw&YVVc$Vvu1J*&5v)^4sd4be|uJ|dM@X>d*A@^uS zNlPVytDZPKdws_zt-mk6-6^{Mh$+5~+@D>+Vl?}1>}W;$=746hogz%H%##sx-g<&N zMFPEcxSY=*!WM&xcxmVoXy*w3G-0@^72~spccZhH z94LRKS24&W9Gl}!aBZ9!Y(hfwVbopVU33yHS5nnJck)k>2fleo#aoZ5*aF+cWcs*p ziP5<#3&~c|KN4ai1wdx7!Rg3*!Sx}g4rImi8gga4axkH&eoO z81{rU3Tpmg{BZ%_t5z{Gr4S9C`5^YG8Kv~j#8jigSU0c|oTQ`oREhY%iy?vC_zO-W6TMvR8S^Tk;$V*Ea zGeb7|Y#O$)ri=ol(lRk@1Ymv^^Qlz?U^Zjm>SF2n%#I!>63|8hg{ixxbii_9o#0#- zG9PJ}DpER6Wg~|a5km_*#YbQPq7UBv)Qk}oN=n11sL6=&vBlp0)LZf7F&gEWxQ0J2 zxvYF#J7!IKzyJ846?|8z=eYwL33E(E@ z)BU0SKvxA?`XwFl?7_nmyH#oFs=um?A#Z9W?!bYRLb>CBcjC|5=!l4Ew85amO*uLt zbB?p(GI;MGd(*lSKI++vRU2?_b-a~qLBbQpAx=l2T1*!l{2sU0!mZKd+(WBwKu8kv4R(%DgO$5+SG#bNijFVEh zU-zHrcxwRN9tV`KgpjDeB1$4CDr{OcX!kab5C?pQ&8%SZ7faA0c@Uw6lXjv7MZ-{p z@S0~=&#@^cJO3?_(-vW)G47N_q(8W*X;rDdf(VopWn#2Re3fDO0-@pv_S7339U;C+ zgAgt}u_B<_j2g^OB}p_=@9ov&vq$QslM}Fd*pcOUU@ES{gQX$+{QO0!6OrDfe@Fmf zzcHZ7#RP|2f)h`O1&FXikbbR4=#g{Q*kj;ms&V^_vHrL1Amw^F>WCEExzob-SBz_N zP(|hs6%1D+K&{(Bg8E^Jvhz69rxvw{q(hrN(jc~${-d;F<=1^M3E#$CiNPJ5)sPF< z2@bwnm5gTBQdeXSI&_&YeoD zEY!SQSJH`~Q(R?fH2nyB9>#@v3OjJIdmqnIzD~8-4b@LEmxl#@fMuCa(y|ib76f`2 zlY8J%geDhK8>^_VNN|g+~ zE!d3CC(6eaN8L(X2rM}W#><%yL5lb>t|b22p@RjNbTrxdWuzDP@W}>R^2?Z=T$9DE znc(Tc3Br~udpy^Wa)*N5lQG#*W?a6lYqc03Z>ps8kTsy{^9DFh+q8V|QY`miFu5I9s*t#6I0Qh#K$|*Igxq(Wx1wu^xReHzjML zB%^CIgR?GJQLhu2Ds;40Yne^dSy8@Mq^jH7jZ|OQ@Z28THvirRem#3LzKr<)g|4~B zIAavVli=T6XfFDFk;x^jdlFBLvMDIu}z8TlPFw{5}B&g@e7p2a`37DYwr&`o8RtzflEa8 z9zWUqs#-md7_<(#A*u*}NGF-O`vCn=EsU&pMImL6hhwy`&e4d%%fAfe=E>7|kuqxO z%n|7RuqVCi72LsrL%bf2Ez#9zCNp~I6NdW9&S0VWW^}U8d}zjytg}l}zxxev*UNDF zcr?Wc{lL$~%9myY_=&feBm3i1hJtYmWy}Yd0$euz=XQ@a&TGqc=O{?mJc7-lqm`_F zsqZL?s@*h%L-IqJ%z7DFLS~bN>oigUUdcP<8I1=Rs!qT!yas$7@TQ#4r{)Dh>Ei(+ zEk^s3gQ1r%g_$`}n~hxAdWUu{l5DqDPl!N67ihxz%k`vbdk^a;fAYi)h+rE`H|Ohe zJ#Q&Mx}HxF%b@dJ)I5*d>q+%e;x^(HH~uogH9l*#c^6&kL1Bq%EIk_dF`eClo|jl{ zAH_gojjX7pI9-GnVjm=ULNd4vIX@0w%saAQ4fd6@M&q(6cnWr?Sqpn_5XBjkxEc{N zR!_q#z13)70Vzj~bstnB)D23r4h?5=79{K zY^-=>h=YV9_WCfX7{7xQpYYuvKX7+I`lu=D_mVPF2xn+SO zf|fD5$Q3c%KONjb9O!V$I6JC868^rKM z&F&BncPPhPirw)Cu!ou7D+EUc`epQFmzILBWK^iA_d8f@R!}53woID4-w~x)fd~E` zN}zkZ7ew+*(hw(nQyW(1eyfbM%G`eK!XGazEMj{G|5Hb;Ute6ys(;*7{Wq7WZteWK ztDS$lN;}rzZ@L=%?Rzz7E&p3r%m02oEn64At-44Cvxq~`Ditx6h_rw;0DGO}vH?Ce zpU~OaG`ln!2qIdF3C|H-(VEhpv%)D9|IO%hv@fbsT9HVt)>kq`Z2$0h@WTilR|_-; z(hq0`2JSD$ULGbkAmo#QNOoUn z5T-JXZI9iCYHnJWPBmipnGH<`Q_tG_X-0|00@Zy0E5_h%P-h|u&e@i}lEltXmf?C~ zEi6I;#!X@BT!0QJCiB;CUrk3irfBHcNORN^Lvk{^fm1>!oj@r2Qe}&UY>{i|j=5*E zux#Mx1DW5-sSmNm8^-pmj3UNhfV24<$njNSSLJ9c+Z}L-f<{#f)#oQLq~3F;0~p16x#z2U)WS7J%h3@L$nUsUZjQXZqr^=ed!=nQV&RORuHto*vEA(Ki~ z&237D`4ZoBBBfo+L0a{ z@5;=bt=bg_%`Ib&660Kbalr2siv!PB-v|7eb`cJFDYB#VqE&&iOScdZPE&^wu;F&_ zfU$EWr3DcJAc5hJpf)Yr;KCq->F}@k`ebr|gO-1QLWcO(qR1k%{`4F;D^h?h}+gS&utzz$OqxQafP%4e=VPSsY2XFE=Wsf*bn3Zy8qjHg(F?3g9RVFJJlExH#_ z%(tdfxOX3a_w>=;*3QneoxK-Ze|%A|(6p4aFM|;z`VHgo^yoqhd5nS5v#IW4IkIa7 z>U%#q3{K2zYXY?j;_JKE2H~ZG3&)a%{Y``sZ4TB}78bVI!0T!+t6;>Z;h zte$*>ta_5-%aEvbfFuVF*ao1-6lDgvMXpVSKU0Yj;-eYvp%{_fOHMM{+<2WwNkD7Y zFs+G?b@BRd?)*ud{=L8JF2JMjb{cQK-Q0Pxz4@dnwX=o066H;IH#a!0-QT?QSQm^? z-u$QZe7`xa#!|sXo31qg$)0vINl8A8h)Wa3qoYyB_NLYm;G!bC6^b-v?MSlZ4TrSiQ0Ui9&({?QylW0RNK^?qe zQ%X7xW8j9ZwIQG;i8Ry#7q%EKRQ#!}WFMEE*00p8nK zoF|fsW$Nx&Q_xl5WM9L!jaa z&WxK+2;A%fXl$=uW@|N0Hs@ppupyxHzK2I4?iu8`YmJ%?N!i}gZLPNJ*P>tDBjB5n z^cnl}&$}mU0}`somM$ITh{c`x@g_gkikU#@bsrOjhuc`dEecnSyLFs~+7n?@-jx~9 zwtMUyuXMn^9LMr%q6>Bmn#v0;oaU+jG+=(ZNK8PPX8+h2YCLe-B(TaQmhXH`R@3yH`%sg`*oyS6To;cdI z@OP`X}b;UEpznm^6x^e9UJk##4m7C4)Qfth-;K?nagGAJRbRq zE-YIfMsVrGvE(hWaTPRe#mPu|;cP%{g$6BGLP06}m8Mxa7xJgpqFq%ibH1uhr)OoqITp|Fa+)hC7B7NKzCy*Bn|5p@SI&`&8OkVF!#5~*2H~6@ zN|_L(PPTb(P-DZt74*wU?)-D@&~!QNkTe@fIx7Ppdo#5+!9~wr2wORLgfX;qdXjoU zyCV4)rvD8T^}2?(zS8R6C#G)9SVEI8b}4G9ZZhe7K~vX)gO zWy-UIA$U#v0~PQ-{8ynx7m(+HmQxxIOGfzifhZ0#1;%spc*^x(?kcOO1I;0y=Ei?nNq>1V(Kc``N1=-MfV%^kE zN2%l?Zgj`|RJcv#)$X2jVvBm>s$3NUwN#vFZNON8^q2;$@K6=aukwM64Qb~jJ?F_Ua=t@TxXQ+}+z*{-3hj&uJQX&GmxVXCaMK90TFHcq~I zd}{+MwQmQyG(=)W4OnUrxGKSM@8KzKlp>H8>^z)}U%>?}{ZKErHDvA;5|#!jF}kWz zTTWyPxmwDG$$15RIswri;9YPqHk|}4j?xWlO-w4i4Dd8VqG~nK-M!&q5P0x|yc2$$ zK&V}ZCV0!Oj-RIlErAGp^6eO@}A5ua>-eGel?#lR-PCUAbh2^O@35?$=3rRFZ zE#$tk@W-$7DQuChugaJBec@$B-N@l^Pdu;a3OG=_h7%OF0>!0}_Efn!q!Q)bGoVj1 zlDFw=0cXt4HUm%r_K>ka9ntm9q5gzzhP&ALxg>oX?Ljr^y?Ph^7b>m}81_5NxJ%B) zXRbd5yoH)fXUPmNob|1>-kRQd`nz6w;@K)2klHHBp42<6p~U+bv0 zoL|wB%MYQr93E-g%fb62T9+${?t|b_oC-RrXqDS*63N@6@xD9$Ts4q-gcJrkO2$wl z3CY`E#!Y4u*vzxTJpA0;>0hS-PVZXGyTyl|&W=*mMLp=tySBE4STqcp2WjSH^*fPn zKoSBpgN+e$4d|!h(1?pg___W9N?lbR1H(iWn=>ZDTYEOz9gSZlO==|MLJm1g!?YZB7$$_Mx9yZ9<-orSEdHE zfvYWR>4>Wz)Ie~e;x-Wo;*%*PmQ<;phbJO$zb$igXoT?cVGx_x@^)oqBwYoKYjjld zwc@ECWP3jx6EDf3gK~JDR|K+@+0?y+&&!F;DQyIEUbMzvbJ{5%jhN&xthZE(j_*P6QmuN>;nG_DqXl0)>~btM_!lKOE$PL-_eCpX0zrl zM=X)MRWew*Ba(a(_2;Sl^gfU$lFTv)eGta>3;!XL8n=4%*oFlwh?tQXQozH)22I6L ztqLTsYyK#DGEMg(U+J8qgm{gQ>Pb23T_!@p^QSeBac$@~Nr&wKf)J5AlF}VF8){^X zpCj4_chr?@1B^=IIv>qmmGZafT^59nkEZZa1PhA=V1)&ARG^eOWIm^3j%b=DR(khh zBV13L6sT*AIpAxaL4Yqilx@&Ic|u^kbn4J`vbS&G-@!}<%mftuvRUrfPFFY{0fGAQ z=42AFuvNuC4ewIb5A{y75o9G?d$23t3xRjn9 z+K6Qrq*NL}+mr`DFy;LP!8%nOX*fcnYaWiK_dB%?uG@%r8v2F=owf#7gLP;cP6a=8 z9}z^u9E~R^wsQuzj!%G-EL<8F$ZrkCR;>j>&;|s#K{#6_o>>(q2+_}$OY)}qyPS7G zYw*aY3G4^slXK)cALL#IpSlwX7>)m{ZWtcZK~PG57!H20@RsnBq{{IV4mXT86K0|> zDgw~up~Xw0_&Zb#=@nb9+LGVkA~V}MF0#-KcQg~O43~Ln8!gb<`l+}5LFF5A>ZP48 zchR8UaPg?#6RuC^XZ`QFY8s=E zAMlCk)e?PXPuXuD{Ag)2sy>qOGAAINhtG_=+E#pG3i}cF20;Z!{~cX?Z}ql)GU`g6 zK-5HTv7`ImSB>iE#UH4DLg}l(mOg1Q!28P-KKye{_AC*U=_<*R%0Vu;N)8Yj(FX2D2_*>3dyMR#Aae>v%R!(^sr9AR(xMNCXwL(} zv*)H^yE((0jiSEie2pyax{5gJP$X^<(4mON$e#q+O$ z8eRhuTU8rm)_^S<;rGvBn}~OzJG}lc*K?Ny#_~Axk`iM4=*9S%WimpRgy{rTP2dpP zLj^-M2;)SCucl)tjP|GaW%B&WA(DC=fm*V_mBRw(?v=5&?|paw$+{QvI@p`^5qK=e z@`pRW3=dE_5$faxvHa$QH5@ZK6>EGXnNVzVnFwTUwDx&_j%sB`>-<70jiwmcX3 zRE=j0&y;5Pcm0z5g6M!tWrxMU;#kiv_)cYX>9b|fMxRYRS?%ymD*5n);GTlz5$LE>PB>`i<6YTvJ3?;lB5DXt(9!eg^ecH4;V8r66g z8QWx^y(j8}VFVP;pYen|$YJj})aKA?NML@9m3F>#`Y>66xL`u`ygAQymC$2d=sE{x zm(4x&X?m8qOjmfOM?+d1v4F?J=l)K@6%r+RJf$=~N4lnE_~n!a&3SXf_1D02uiG{smcdBIYiucj}N z2xq_-A?@J>81GeM5qWxdG43|7?j`cxe9%4E;@C`UX0;OnU zD(Um^`}OiWT&^pRZt5dZ0XRy^7vb^n3lZiiZ}Wd~I_gdq4joTu*Du3rW(#)1@STeD9=1Y% zrS{%ge2sF66SMs*-t=f>ldo={5iiMr5Svxi1f*T5-{ZbDLe0`?)tGJ@+269S!BG+R zy{Bb2nLxrASiD~Vvl_et_CmyH0x37vm&&H#dH4*ixBcgCor2FT;h6s5cZGG~uB2f%5E|(`f8P#{Sw&M44NkN{uF^SdPX_ zoB}IVuFR!FbC_E|eTLJ$P$h7c&8toK2PNtC35OQZ;lHtqZym5GgqWAJo`r@mE}{Ml zFyMhg=72XL4wM7{NI;cUmjdPx7cCz&sI`sM`= z1`RT1l(2wvDx{8`zE*^wP)ki5<$Wo70=)$-dq)scY=Ci}cN$qS-;|R@fhivfZXLDrG#>5$KyTJiIEa1W8hJ`V0eS0^JOGe0uf*9_zfa zlDh>Pz8j5@3B3&?Z&+X3G z%p}7+fDu%@vYx%ze+}Io&Cu;p=(e+F^IXvG9yz~+9KNs$&UuX@dRk#I2@{Bdk(|?k zT@WgM^&YDT1pg?p|IVRAgjlbD>;TF=88X6Q4p*Y%IqRK|nOBVnLAouoK%C$Ku8Geb z0>Eg>?|ocQ>prMpyAaZHxq?;2z1O|)pz>aE$Vrqm@jVEXw_&%}_D1`oqtV)v7`zO5 zMzVl1pGd{mMhbz3JhCRI=dPwS>hC0H(B@I1p4FDX|Yx zYA*T-#9Q(nYPMHe30-{+qQQ}Kc~(1C6y0$)vK_dMsj$RLumy2{z%rB_i5a$EJP)v` zx7ojiI2H14w0k`Nfg7mwz+b8geX=QwX!~Z5o23;7u?`RbC^UIH4+w)>^E-b#9`5V; z(F$ciFN)Ur@!{bVsl)Mm&;-%~TEzBnKY%_Q;QM%v{MfP7c(apwo1RQYlFME{5xAtk zT{a;bI+HbEYBuFM$|Y6D1X;5jFH^dL z;F_CX@^y%PL@a4+krTm!GZZg?Fb1F5*Z%f{dyt;)>|_zDqOrli-+SHk-P{Apk#C(#-~2CMY`eTj^I@)5Ahl%Sl*N6woc7ohbS*EHD@Wu z(jJKr5+$Ljav<{&?0PVFJF5P3&(HA3`wt#|cjw_9En6dYPBn$zMoqgBWXPb;>0ERr zyp`p2-IFvXTb|1zsK5dwa$|f4vDaJACsRQ9WI92bf2J2K@>*CcYa@YdN^7B_Zqsge;6qW>AK zU#(oK+B|$;psvutdG0p(V7~%lzjC2O}E4tSCW`)9vOs8TEIcQ@-z}na* zTof(RoMo~G?)(IghQd(9dlxU>pB|0AzIYMb69QZuK@bTIal}|z)^ZV+6+^uu^_^SQ zx*?*|(wKv9r_=q>a5A{u8$csD;$KOX%MbU(bB&)Kj-KE7lvIEU#-2Jg|Ytj z4RD3J6^P4m+2Zt9=dQhG5E@tR7pW9PW&Tg&(Q6F$btYcCx@`3R(>F&WIC}f4v`}P5o+2@mWjV~sj;WVqh1RH`Bl*c7=M-1T=DvfF)c00|)DX^3 z(j8QY1mF`&wIlMx5L0}7j-jra)!8c}ZlE#;UtCCX7T%BViiDzigs!+4<8GPqt%O`jF@ z+JW7U)%9|3g54H05&Fw&CUVe)5XTQfftS5rE1T2cy@j4sCu9H+40u5?B^+-Kp4Q2< zotiumS>?gA&a=xeW&5M}md{(B%4#dCh$D^!3ah5@WL=eNu2I*#;CnD(^M^Cu+8&q5no&jA1GhG)Bm5n|lVIwRvZB-qk@C zZg0@lIq_7#FI3WNx`SyiKonQ&{CCl0uGq4_~2Bqt3~k+_@UFMPgnuw{ixl2 zg6;v4H_eGinFkM{qIECL0lKnM?N3PF)~CNf z?!J}le23`>Y z((x_|j*4ufg9km}cG4DRiuLP@wnZt2$pm({=k<6ou~g)pHR<(K7d8KdyUTQLGDa{S{jhz)Z>GIY|_wU zdN|w~G0o3qD*}t_5(0q>ed}>7&u%}2%PPX{UW|8NAk=vXr`-v?_C^$k=(z_iR4~4F z)MS7=5`faDLER;I7{U_!sgRSFoT-uw34M#l2i+a;B!)=72&J!wwU|!tGFsJr4Y&|4 zOx&OoKG~j$%>GEjtC+Dmz1Z>B&7l*v6>twTi}08D%zcICb)f&AE%E z-!BzB-`e?!k`R<%v)l{$RJFHIzY4RV6ochwhWqSkzOC(^RNmTmZ>u(;Dw;+aJ{*!> zIo3`iA$@Wt`02A+o=qOQ04F00acOPqTh-YJw?CS3@qi4z-sg_RovOUP$btF}0=$ml z1PuPJ@*^81z~Pl(giiV-D5O5)#*Yv7vTm5Y*^PIEE(F|3!q7@=@hfpFqPqROfo^%n z*&ORE^H~IS|E|^RYujf$E(jP7r43H@r9|)L-dY+Ag=W9$=>rHwl~c6c)!Q`JWM6Kl z4|xU7#;{KHe*Vn!yZ`)|j6vR}-`j#u?M~kx4d824yhHaK{OQk-y%Tg+%3G;4X~};~ zsq`8qFvKDmAR#14JXOISVIrf#6L4?`24%%D-B;ti5pt6fPW05aJwuFrszr}zMIzTe~de~#WrrDe=21?PSvV{cn_0Iq=&r(VHp zIF$JKb#DzM?8Vv>zqF{ck$Gd-r3g@!1HWwUOE_Zixo!&+k9M-_A5&&P5g`bTTwCi* zTF(b9=0Gdd9c};vj1C3P`v-*%Jm!vKbP{TC&M&6onE?)S z36$ooO`=Ve{P<{XZYkb8pdfUIg($Va)P028zLKyqFc586@8^j*{X~W-Y&n>D(YEMK zqC|Oaed@shyS0m|%Xz0BV6jUi+XRT&@O9N$FpjZh>mLs32qovZ;_1QVUQIXjULac>2^lT)nfOJr9$37gMi2-zY?OV?n7@?Bu zpmIZz>kx8RZfK(|3v2}7>!poI0s3jxTdFdPjx)oZg3~g^Grp8{UG3dPWcO1#pit}) z2KE)4nxTpYkB)y~AHcta-PfbxOZkyzs;xV{jScx3ICKDUouW1DXnUjn|IAT=;!B$e zX~8RQ-B#H#%uaemq3P+P z=`kFe*ZG}-_S#wi76<3qmv(8HeCV$AoiCWvtHS`t&!Q3ZE2+N z(e}O_eoLDI7H#bS0WED5F52F=qi<c7WSBrdiotAVagib%1 zpv1WZ*=i`lSjmPQJpV3iU>90hg*1z=l7~nWTxm*$?;`@Ml{9D0C!eUwz)cl~D{&*Y==eUi+F*D;~;lE5C$zZT8iOLCsAh z4`&uaf74b%aM=41}?PRLke|#7r!75EZuzGJuv(6ffbCSC!~6mU*zzRKb8|} z=_#-|J{TsyrQ!_uhG|+qYnYiWa3Nmb`30x63$BFq36Mt#c`5*-`v?cby=P!5lzM;| zls%*=nI0U#lO?b&V761e>Edxp&SM{eNDB-khLsPK9=bNim_!RgF#p+ix|DStF2N6B zRJCq6ds$syzJfhW?FvU|yR1#V(Wb~CZb{^4qeo08Z=>-t3#PP{l-_-`!m|vCWLqPS6;{VtrJj4gd8a0soJcpR17v-N{~WzR4FFV) z5Z}!w1rU`ny5R0^&XbYh6$2~yT3dQ-2(@#WPb8&W;EQLl<2{R~XWc^2$*DP>l7a-<|kIWRvVB@e7^s!*t~_pf0`_aj!0@W*JMrs{WjnNS08Oa z(GMcw79F=y`~fVnWrDQakZ?D83NBKE!~Zb)WwaakE`mTgWwRT}V64iKjYkUmjf8;m zE^OX{N^4b2P?+qihqO67=(hlQ0-F>|9#0OBX;{~V%C~r_ejQg}eHo}R*smVi$zbzf zk=t6evjjQb>WrYH-8haE;4ysnB7?fLim1p_^J_z#Oc}vfSF==%hLlxRKgP=Ti{AYj zs%ATvRX1Lg98w5gQkiBAO(0;L$&$$vEYF#!XHJtk0djsv2898%2=6J8LXG6q3|2=c z=Ry!(puLy4{mAy@9n8JxUC)&8W_L|4As&23TrMaw3rP*i=; z=+9|uv){Hz_-HOG)62BG2h}mHwi;FLcT8GFeIzEJG^+Azc0YCyWRz7-^5?(=P`HDE zn{s)x2MaxQCPygIWV)PzN^UBbHVO3U;FikL;Z zZC(6*nB-U)Wem2*gipU!nrs?-O(Lm@vPku>qHUr(6`su=*ZF3$?Zz{wmH{|Ao1kxY zYN|Hghu|dKG-#snV^?|`@vaTH9j`H|zp;S5KchSkTze3fB8py?L2JHW?+WdG75{^Z zaiy>8>}{(m!JPTl%8Zym;YkmL zR(_sD->q<)qfMR(gZ*EsMw?+$nN11f=-UcgKRX+j;6Tx~?AAWL&Tg za3%Gm*_b%dG|eRi?eYAshP5PLoCee9@|5fd4JjC_h*R-vA?_D0tj|$h5dQGkFr^-} zw8)$BVY~iHNW`n04EjU@6xsbNQjt>F{&PPFde|+cP z?mSc{Pvnb*%1w$)N$ARuE5|IWQ%lrjxznw5v-J52daEs{h|6#NtVmxdegQ8{3X?+$ zv<-RDKZG1#Upf$1-$7gN-H?s%v)ZzPak{VsE*`x#PKeBj1ME+TmQ54A*fD8Y~1&uF6P=Zjak8P1p5RI32w+ ztLP#l1-h{RI$URcVTy847&%K&xvBA2Gm{|T+IV0Z_(RxjVSQ_P2wj_f4T-Uh3@ z+XH@`?&ja@rm7QbB~j+vr3``z4f3R}pA%z!)vM4!)c}ozUXs2;D|DEtJv+a^rxfm6 z9(q5x1nh{D7G0+a{7{f^iN@i5d5E4LkB@{Iq>Bvm{Ud+a@nj58ax)F!DPYOr`U7)= zKFL);v6T%x36kv03gvT>lp&|w^2O z#&SUO3aHWk@b5H*9;1Br478&NekUIw4QF(NcqfiJa)Y`qRMciQ+uKsKWzp1Dzb3yQ z{(UT`%We}H;oa3m4eiquDO5H!?Q}I*PA2bnb@l@p3zd`Rxu5h2{dXo{s2lqZ3|X`_575 z*7LMoPaZr3f3b%uW6h)WnyF(O>2&Bp$TdfKT3cf7K zOFm28T3y5Kl*|8q;43K2Xz~7VJ4qn06}Z&RHCK6u0$bcfQ{XGHcb!7ELsjUN><8$T zo2|5Ug&?61{+ehHX_WE~GL<-nAO_{8k^b=liQ`FdEUlpb1omg{fp;ZhdnG*@Yrbj_ zn-r6Q4WmEm_XZ$rVLClG=6In9u>ER4p< z$xjO@N_XIqH~@_ZcQjxlT#QVeQE2J6oLDSbUOD%ZbFDI%M`0oO*Yx6mG?^W_30ze{ z^s*MfYi&te-6Xs%%S-Ra!8^?FW81zxsz>x;*6^OQl7Ze#=Li}!U+vy*S4yJGg^f0$wq}ZQn0D(OzwdvPNT}`Q4fm}q0 zUq>MP=$GBmXb-V*)WhAobML{{f8W`8gnw3{6a@l!C=IUl1q$V1EXc*jM|6|$*#$%- z6=vz`VKRvjn7q{z0HynKo6MjVxJ{=|;;$YUpy$@7Fdr$d2Pc+VC^*Ts_33&ka8Tc_ z%KNm;LWzLVWjK-ba?))8hOr7H@KpyZPE^l|=|9BFM83w`2E!-2lSr961q??TMv-co z8PJ8Wl|dtll51p0TTY+72)E=dXQRDiW-$|Nmm&@%GHN;j973FxC{<02K;wtq&E?po zvIH(NIDgNj9^li_?vP@z#<D4ydxeTr9bY8nJV zJwOQAQ^?WqK&J@}rqJPRZy!m-IX5~F9SeIfo$WzR=-rc8+A+LnHa?QrTt*fzF?s?t&Pr!&CB#s{ngH>A}G7LHfc)tcis(pbqp zW4?Y!{ocP%U*jd@#(a&xJ zd}AONGe`u(8acJ7L2u)(iMr^7a$GOs-XbOjIQnLuYg>Y zSG>1hd6(JGl@7;q8X$3e&^VNaf3hOu-)`O4;#^*1Tz>e^JO8z##jdsH_vSZ z_tRZQ@+sr)tQ9(kK%LDir|9e9oy~{;CUX}rOetNz{l_P! zpzi(2eXh5^dUC>GTG`uY?%R|4*8%K^I)*rLy@?{jL-EcpyfcS0NJ-EaI4A?jCTmBe zJ4D_hiHm(to+gB!2|X;n-RB!jvKD}qsf1W7bh7+8^U2mnY?^9s)R6a*bHWWaR1 z|GcOoJcrx9PE)*X(RJ!yod3bF@F7z^L5MEt(@?FEK|x~NUItyHpmzwWPXI#dHOQt3 zs=j^jqXBpfo|lfD!|fmyd!&DW7F0Qlp;# zf@kp>in{4sHfPW0aKM&}2N8_YyHk?wo01qtev9>3cQ?7!-VPgKP6(Q=X|9NH16gK% z_?iDT*9qA$C*=*wE4ZCmt3=N5fg7L~UsV-GgwhbiLFT9Ky)MSm>aweOLD%^x}C z>Unn$4(LAyFsB=|;J2?WdjbQI?7e_e z(AI#??%6_(AoGQfIn@m`wLyH8G+32sOYi>@vuMth&m4~brR-|g$mCBnHc-f^6O#xS z(Ph)Y+dI8hI+e+6@L9P`u~y$^W19Jv?Eq$>53_o#TJsExCnsusz(2@R`u4%R&j(M| zUmP7Betq@o(luUG29(xrd$?$999Tv;v*D5%qgL`U_$GYl&bpbSXkvDqT$xIs@7%OR z21{oW=1V_T1S9B1!DXn%V1cCtd10moFsPwTU^2cqANWVfHR61x0pfpRv)Zy~k{E|X z7Qs{ zkQ|X%7-$(0x~_GTX-gkW#T*+SO1HZv8ow)1vC>;vZh4Se2acBZ`M{|)aU6_Rjl-^{ zX0`y)*!F~S@`!X*azWkms8mshM07v+8quaWKMyxhVPd!~mwVR=;u#eA{BjOJ^^d_- zP2Mb6nTpH=>d+pk+;jiaJWqC2CS*&zR!xS~Gpcs0Cj_r0K&eNe9*&#q9?=$lUsYNo z)X_X)bOG~i-MdRV>vCBo>XTQLs1pgC7$Y}zJ9Kj1-A38Zmf6W$=>W;vM_;uG%64{4 zthA9HdAA09SaevLu^lXx25(HUMw!JDaB>-C((e}C!T;vzP=Gklj~J8BWNh^E`He2n# z?#!<}ElYGj+WH8U%|{YG3T(U#$Hq`Zw-V}yBh_dP1gOE3?ZV)=C#ovVb3hgU_!+fI z0zu$cRM*4{XS6?}Up2h*gE!&N&&D$lam8P7Rzv9io>Nl=--+_r+G@Jhj*hgNVRujV zJi4OJa6Zl6SuwB9o7awBmM#g)G<>JMGlITGC1@JRo-~={oXU>x-Ep$<+OK(4d;5W0@Usz~>KufH9Cf(^Dampc5K6O?Re8aUYxyJ`OpK~24a@Q6t>g(BswFe# zmx#r=HFk-dqrSAzpy5e*uks93rf!W2E7P5Og#? zfY$~@w$~`JikoqKD8?=cqlf=Ksg7KilHZ1+7Ja<;sPR8~6WzsZ`25urUj8s#JZ0t6 z-6`}0>eO&Z?IG^1Y%u;oH(4Wqp zUp>6~>Z_~r>invP(0nuAyTw*T6s2f&0LPMuvGH;IZ@2r$-QZ-oBB7X-rOoHlUCH_# zx>FXx2}lbf3c#d{E*8$|ZGTuY87Y;aH5v~k&$wwio?K}1fwE>Uv!ST_$T#5QK zxe{GpRs=v&fvE;upV_rQ1mW0+69rX&zCV3B+=n)R;c@^1m^V!sz^y;noAk%itL53} zG5<4fBXUrtiZQWiE}py|0vdVm=nn+aT>h6ZC_M<2BMoP^&L^HlTmR}*$v2owC(OeW zNeo5&jHMgj5sR#DyzLM6e)s4Xpsjz0O5EYYm_<%LQ4=Ewv+4ARMbWHXe%DEM>-k|Q zWh(|Au?}sFm0*K62mwm_*}}9!YGdpYggiU=!I2@wqUQ-`^yt z&F(eWm23M>!%!nE_4p7ZJ?Btjx`yV9s0C$vR=i|dZ~w@Nn$8v4(>2_}Lg49dBG<3E zAPoH0g;pCi*brA3a8zi4ImRGQ_AV9l$WQn04<7H_hL!3uL{7UGN%G_#mWPji*t}n0 zJX6{@oEWH6&?s0<@M>I~)CAGNFM3=E9VF4z{>V0nr)UFa8{pzsBHye5g!r-p9wSPFZDM?rl9I(*2cY6ohBgF`e@P1618>-DNc!7dIg7v8NN_n%vg%xBDlhL%_0 zV(()Y+C}w7`5oQM%XT~PAsN%s@t>iM$~>t)zjR3#`)3_j&b{_pEHG44#eJK@RFpbx z8Kh%7)7(NBiQc(=ebu6bc8xNaS@xDxqI7Foclz@e$IqVahyU2Y@e$Ay0y)KGzc$6; ziP$01(JJ@iCS}5R6dGYGAR*LGpu9G20%f}soqyTpsJG;O6ID&QO7E+d$s}B`QR8Nm zPRg{KP%m5XXte*#WoXH+R{(WX~=nKKq!(c|e4L#P(RA2E3@k~as{qeUr^Ap)f`h-g$Z znd!?A`i8UH$eO%)v<^DQn3kJg_K@44kMsqpCz6|D8e5C328oDShb3pi56}`Y%qMwF ziVyE)lQ%9S782pdur?n*eN>-%bwGI$upV#1-Of`p+?gX%V{{wqKxT&jZv(Zc5S?Wb z4a5c+GPIYNZ=r|=M7lDEqHJk6H{|8d^0&0!?)<$OmXtV?cwSZMS6HZo^xU z;!?-@RR^l7k1??rxlYnFL7<>sI%nQ}jK~D_G)#wfMn{lfD)`T9b{1`zTE>Ocfz1_I zwCK53ZqaiBQZIB(;*8ffdRKKigwWoVt^0Sk?r%N*FIF8}yMlL?DX~;ekT<4?BPld$ zmx;suaQtugA>Bn6M7gfOsMRd4Cc0GS&^)e3!fuO1o3@*Wqy&PB*WCYI+gxAElV_Bb4ltD%gM=xpDvju_4bBysOrLpzMU5k zX_}F@l4eRc#D;jh0A`H)bUl|f6`s{U^Zs8Y^_;wn{6Q9w>Vwx$*`D8K*DjzZMCTd! z3@EX(YB&gZ3Uy5{2NCc=We%}(X|F33n_}YkQu^_)I$0kP)!VeEy`3HSo!d%wcEDJS zCp$ZZs2BsWvx7|0Af5A_9WW)u5>#5o^Om;4GomG$mIn4?z)OrIaHIp3xBbWTx+Dmw zvH{N1UcGqboc^P`lOAv;Z=sy5tTMt#3UzO2(^MQZ z2b;1}YZEdhCy|<3b+s}^?|M8@EXF@HA1f|fc zYp4Ql)s3j?AJ1_>7)nC9rdGvXDZWWZ(=Fs*c#c9&d<30h@;wShg_O_$%4Aydp^_|H z9o1#Nrh^E&!UcMAX$T@R^q=VG^wy36Jdc7*mdz@I3T4BRsv0#=sx5PCYCOu;P3;iJbq?!+L%i!}-rLi0>&lz~gu zZAo1$pg20*`ZoN2HozZpBS33__aHnsibr_R9K3|5H@azobtr(6pr2T!&;prmk;-fV zviZS^eBuz=hA@g3q62Y2Y^cZ-#nTK`NhW)TK4tz*Wfsv~Ua2%BYExlSLmPQ9C`4km z0_|5vk94;{`NaE`t7y~XkX~@u0mT;1C!H0{mpZ_ z?#oh&U>;X~zu$+RL@Qm-Rq3l!r+TlwrS5By_#W2chEpr^zghxY2*R?H01rg>`N3Yq zMw&k+9^kH(V{y$fkY$?zJllu@O6U}ujki$~Y}DVMKCh*RsiPeFKo{Q7|8fJO1DRd( zI^T#^jhkENnt-`>`+3NaVv8?XtR@T6!Y1uwfV%FUxbJStg=Kdvoq;Qe?OPmH4alIC z7o3d5oNO=LolKtByvfknT(KF3B8dbk-OKxNoF(4hkW=O(r2su$nr<@~nIh2GPblOf zpK##3Ga+>!0YL!^6uwVzt8CnWYR4+1{}@Qe4>j}wmxKg9jNNfrRj;jm>+9Zn5~g?Ki*`v`Y^Q_pL15h&iK zDu+6#9>TjB2o$S07cOBw8i9QA{(z1AGCuw?oyBhdrJIL9{%i9HSlE>1Q}7DkNT=VGSz3=7L-j%t z9;neFfN6F-%4srly(W@d-K8w)ORSiI9{|zevn-W0oEV}HK-JhTcv0gk!iGFItEKRW z6G#q-6i-FcbtmXVDu{6dU5@CzpN}S^8Q26tsNETRhe9TL1*U;Dva|$iOb9>*4rv_T z4;BmC?ki*fq5D({+rpqir^}vb{-QHn0qimN1r*?0=7V^jG~m2ApYx;vMm_GDk{3La z@AR#mzWcc-1LY55|KYmo8lc$dbD=8B(2Z~3fO7O9T5R;M3-##V0R8CS#OHf3g7#4> z0yRIK`zVYN-gaQ{ztoL9h6-kYJRp&DDOM}KFE4;1WsN)if|Q&G3gi8PGI-Z}?=JW3 z^G5F-XI1%zmzonQZDU@>aaHNuw=CMVJf&mfSOO9x!d$OHNQ#=FVA7ym>)xuWI`LmI ziI9nXa~teWvr{3T=TBdy#PSx%6NuF)W=_Rd8tc7MUL}1)WNa&*TS^=gp%R%xNTlP7 zureWiw3QxmxRohl+WVDgVrf^UiskoDjV=a}zHHnX zNz_V2F=Wf$oUwk%UrzN!g9-Rijm(?(SRofl(n>worz0evViDrFHT^VuD@jdXoQsCE zBj(Ai^xKnLW)(8GAn?YqG*D-*F4kc>rVnZys-Hlb%mQ8svtHkJVSWS7f0BecQU1(Hm+={wIu^Z>BDBozj0{%AIo)U?*ABX+lBqoyv zgqnKdY)&VF!-h7=IDT5(R_z{*I&pC|?&OTzy*qw&)0pY6qSU~6A9)d=%Nf&7G_ZLi z%2mysB1yz!C}RSMDoUB77c(dZvnV0jB?~N<2ym1F{*)#~yMXE?=m>-chE+Sk7SHTh*b zU*Hl9Rh!$s;wEh@+8uHA9x-j3sSGr*siE9yonPAA1uJ*_?Jb-nwoLYWiOJGQUekb| zX3}u?(bG3OeKIGS;I;B5F0CSK-9?|zYWsx!@;#3&tJ@_>!xB{4B@)P+csR2HsM4Q~ zsPe9P=Oh_PjQ|Ry)*S*3L){czL+=Q`AYzxP{SEwqOIi1{BDb~-MQ=)3zteSwi9u%T z;2{4I>H1s2fLU$Ml`H>2?m3$Um+;L}UvF{v9JgItX7s2IYJuQCUcu}6}E7zjOI(wE^Y{HjfMh8fH^*E=hoq zhtO@ZrtjKV$xIkv*mL(01as^)97i0|=`f|PaUfseJr$5-s)SaB02qR!7jL9g1Vf6D z1cMd=_TjA%J&ADmK+foO1){WZP9D;o9uw!w4w^GX&@9saExNlq-O{}VcREMze>l+a zh1j5^Ch#5}CLh%5IZ5&;+i5Rlc4ed79E)kxDU=7F3X@5AmOWjlH<M`Nl=Nuq=nz7`Br`yzXmk zUJ!n;b-_+jo;)|@u}#UNtC|#JT=Q+7cMuq z-4{W-0$NXXUo_^F?u-^)gl?xJZYY))k?m7l8jVSvd~qz=j#Vy>#?YOYN36N+@+jSW z!WT%G2Fpc5K_qSsr0J;m47~MQs9Y8c@0#*j=@Pe2>4m=Si>{meW-k3A^vFFB7!VTx z*&)ZQcrlske367>p)v4xmjgx|CZbg*&yiGhAK~l!aDp5aH=RJy6~vA63dlr;561Ac zarT=UqmdbV24q?bcu?tGP-frl-(zjWRfoY7+i-wpxYy<07ddRq9qd#ckzevb8px#6 zx1fj;jeI(e%eWN-e6^|ANxB9^N;^aVSSxGt5EU0^bJ#IaG0hepa1i_K3tEMVI4_SC zn^eptNpt6a=HCI*S37sW1~fHabgO6d%%x)i!NjM&w{tIfnod%-wj6&@0a2==+$cg} zP|ZP7YQ`y?1|n|u5vWlbo;n{z6C&#R0hzM99v%#T86O-U!167SjyjI=IF|B00E#Co zr)~Pm1{rZ(RYiB{po0A_7#we&OmAXup{Z=?t3_RDs#KwGOF?m(n(X44p_!NTiqWew zFgDiy=6k*23aFFxJ#_B}k?=AxzO0@3)!RxbsUL?k4!lFuXLkpcqJBVHrupDs+oPK% zUg?A0%&3uAve}Y_=pjek712bpUJAPjh>UYw;fg&~43vy3ivKbh`7NfBkV7N-s(J2s z#j2x2YO&yE#kyt7)-7L(#3xF2mFq26E7G?Yi9e9 zk0rjn!4hfYd#@P+`$H?9z1!PKZrzZ4uR|DmEkVybm zugvIa!5UYO7lUD}tXpZj(|-XCd-2M43J}s@Q-$bFnl3-#lI&}*gQ<*F=K_q6Q;Og4 zngK9c1@kgO(Rv7Eq4)B+aq{t9%q2Jokb z?M~fTyG7US8q=2IbZ*qxj(s|Jvxw?FESt@0W)XxYQ5pN-nIjo_4#-kXZlsB7&;mUw z1|2biC15D%-8n|vFgN_z>)7e@6nu-i!Lg~eOU2}_^9y|Vt*OYj>{zSYC7b9}wEIG0 zGAVj%5IgswN^~9fr-r7TSI}lt-*5_tV*)M`0}b~bIa(7nWQT$#&}w@*g)@U_n@*t; zH=`x#mUq8Q$rX<$W9%lZK1hB-js*7-UF35P6+*>xkalZT3?Bd3*;C%z^^vZC$y?$CETYoZwYk}n$ffBIWXl+hrdx_{ z$L5Ui(udSZPz0J-jJy(!YQ{CC5G#-=o1Z#Ec=!!T64@#zIEgWUAuHZ$$dk+* zKSJ8cVw>n0q3a(ac)5^8aCV{%agEx!(#Q9keI&z4H{~oD2u_=S1PVP-t+gdzbD$!- zYYHXfizI4rm82uxv4X269r?5=VL6cZmF}Ye#wsL`9Erzzog(FjctJ_tz_yGbAV4Ma z5!9fTMWi+QuS|bBspbsP?w83DLRG7e;V{}k_!j30sgu5PdLV5=na-8?Rk}Byyi%c^#s+>+Vi-!l)2AHqVoVgUOi!xi@#GYsR%51nSpB6K z5S(bqh#Y}iMn<}UeM2Iq;O`wYR?!r%#yoARcrDWtDyp9_OZf4_22&i|A{0U=|E{+k z6TY=}c}xSb|EF~E@yo0P-{-3Gjz|=>nQMZkQEoy1w>FEEzITiuT4RXe>4gdG) z|L(5&X4WNp=}4B1MDBVb$TU-KW|P%*V~X)&ja7Nn5#>KH6|FMU=w>PX@o!QwQ?m`6 zw1!2d0ijb7ZW7FoM<9195(|Ax$HjYMb)8{dAtMKAHP$tIZj*quYTY`b7)u5nutBX8;+?u11L!=|2hpm&%R;m=nX}_SEe^-3>nFTGG?4-gD zeuCnv*#Brem>j(b==Dx`I$~L1bQoGF5k(qZf7Ac2#=mTwPgRM!Nuln%G^tweunA(q z)U+~G#_4imF^Pkz-F?^_=l1emmeqH0F}$k;1i-ArU749kp7I~BfaAE3y_Yapx6=}u z`>6gG3DHuMD@}7CMvHOkR3o*Vq&wDb%WhLTLG*r^Xz}=+Ak=WloAjYnJwc74Fjko8 zE?}oxQ$!@wgErRs;SJ|LwEyjuNavEGouR?VFJ4P0T91D2{Ro8+a`)eb_1LQUf)Y+Y|yOw>R&H#6=o9P*_ zIdtoeEKA^Nm9ssJPhH7}e$e6+wSf#yz!ZJ0By5qG+#ylf5<0JB6VoDACQooY}+}Jinu%)cAbhGx;urV_xx}=*`uEph{8bhD@@j@^}twynFV)!$CU9= z!?cw54C!t;=6raPIOzlV-&OAX^9m~L!f6PC>*`MZtNz)3@;NL@wq=T__JunXTiz64 zx_NfdTIHg|Dq!wKZ?Vtawuz+`G-6&R(2MIE>hO^7JqpYO8fA~uIFcn0(IwBguUi}I z(5?fFs0w72r9KITjJ;J&0^K}<49Xz37SBFYFOKRq=B2GG?eRR6c+1w4T&9Avs=8$k`%BUUl85|t)faLl_UF^tkr|{%oAX_0 zHG#{OTEeFIQdbgZIm+C#KcSP0iYd54GQ>5vEmw6(P35OnqalTM5Xc*FEr#6C2qlpt zx>Gjelu54JR0YV62JY|#F2faE1lEdri$4TfHkDg)a|E`=B0eF-*7>I4QYh=LXO|*)X1yZwqK`U^gXU_sGbgEVfEyk=vrmVy7Ntq|2Q9oXuTRIq&EVul& zRF2y;@yZ>o8=u$|+%W94JHu_=S>JoGzm=2*#o8@T9V>as=^*kixTH`@Kq|32K9|?R zYo%@6dv>Xj>_6gZwj7etp;j^g8#BC;%|fc?GWi zj6Q6f1*WW26;o^m>6tdMJycxE!^3+wmXK5tj_(f}`ETo+$qFvDO^mIm>}DFK%iO&q z670y*%WmI55a}1petol9&8pK+OgCjqL}%F<3(!vZlOa&Hu;uMVAefmNToaz?IgPx8 zQ7<-0b1o#a8jX4eslp?56%EIUQx$ovWx~g$?7KkcY&dy|TTeqv-13n`X{{l-r1fqE zm_8#%b^b8j)TsMzG|EZ&1HkR8=}Vy22?e%44wg^?YX*{3bnhKH_XMG^j#(d}7MC7e z(p=9)pr-v_+Oly*j;?^^)r0Ytm{Qe7s4np_bmQJH2wgJ(F0%j0WwfAW7D^pR=)LOK zTkB2LK_*1Xd+@A5A^>Z^{DX42#je^VhlFH^yil5NH&oEnc=y9$>S?c?)(j;|lA$r` zMk(`eJd@LNf;Q$EVM0Ft-%kz~$B8wK~2_an_Z#`IAosT5j3GIrrQz6|c&^doAg z@uja0>|27(TO#Le2Nl;Nia9iZ*PR%P7niT5J+s2^44;*aJG&6`JHsc}$VC`GYEXI} zOkdoH0nevp`T}{nrq#yy#qcK(g%7~|ot}8?mk62$;rN{mgyHUkuz>-8%dvtH1a|`D zePZmOK`CQE6BkG0*C)gVGUZnt6OgiTZ!{l2pHRgG-RATVnWe{n&)IRID9NnS{1X+2 zoRO`UwIgH8R9Sn+hfst<69>-$soIUJFqYD733u}TBQ{Uc!qG^S9qmfOLGtBj zVQSQX$2c0oac)F?Zj*@dO7$lG7lKv2X;X6;=|H@d|7~gAG;eLkp!Ew|MwY|A+?#;9 z@i-E-Bx84>rBk?4*&E4o4wp|$V zCYG|`8vQ@K#k)3k;4G*JlXC!XZ1@T~@iQv!en-NGEH1bR6U)sI=cDLUYuSp9m7C?H z_N(J$V+yMxrgqScou|9!1gHHXduz)E<8Alf`Jyn9-)__^y@?Yg7e>zm= z!#Q)G;;tqNfN7YCn{aG;uh&+B5t+}BHu}{F@u;6lNlU_-VEJEPjQ2+iYg%5I_I3Jg zwsSY&)7fKt%?lNK?aR3RV}pv4RSlpB%L;}I9yl|^Vx+6jc#P&m(=Pj12(O77j;qVA`=D84p?UD+TUq5jWid-!S)}KW`8Ob>j`V; zO0G+dV4*lm(7|P>b!Cc)P?ynGq|?@LiRrCErYqB2l|q-boVatV5a`OBPDz`!j}J_i zE6MVLk$<;PEcUEfP&-mZ9;H$ky`=6fniDZ49+Op3Sp$#IAj6+PuCWz(=GD|=r>Lp0 zNKINPXac8Oc%Q>6r3nE-->}G1gM*SPCeWFyJ*LSxRDyI&>m$rEo0`wpL-;_ghl{43 zYLjuGkS2y0ez=R+Xp}-$mCzh2e1OS(lcs`F#l*M*pVK>jP%y~>INfHNDV3uYD^0KI z{}O&L0f27TXv<=>WMvT~o{sKbOYu5IiOFb=JVkSNkcQ-ltwZ#lof&-QN4?z_sI{5Y zxYcTevbn@4?Us684JeeFc=J{Ks$+&0HW&~S4_3f~)%>eZfd}1YsWbaa3)odlGM*1+ z(LlxOAjB>+QJr9&!rNlbT68%sdjkn_a|)K6=!}&_!XdjQ$x#r5b0{Ygx*h758Z=?u z#mj0Ktp5sv6wyD?5$-K=wV|0hEg@Q9v~$hUd6KA-(B-sgl32oHA%O`@Cmm7i;Zg*q zOfBiFqBG5c@O$|V5v1PZ{Y|WMO#_149nCGnQBIGBOI$J`kpwteT*SqJ_BeS}dexfe zOlzP?o?NLkkK^9y3#E~qL^hqv)^B^7By#|%4cIZ?AUi$@uEEEy^CO(Yay$vwo}jo| z)Wf%^`o@{-a+m_;^yDWqc=Snrt~l@P6>^yj=UbXU}?^N9yERAK> zO);Ru3T*ybKXO=Wd6E*aoAYmY?VXMB2fJ;aH1uR>FDA%ZGXlB3Cng0qS$>}A3g8+2 z)xnff0Kr#w>o>yqZ>lqxOu1SYr_;ecsUV%pdtV&?nUKYp{o;-GVOf3nBxX)OuFZU{ zsszyHzaGp(N|o5c=evwAu#Exb92Z3}E{p67SZg?DEY?7siVT#y|Fq0?r958CMH6^? z@`Y2yWYUK+z25+XeKw>nOFgGVqNIsu@LxU^R~_i)Tq=>r*~pv~hc{!DQ*KKnx)O(6 z=Y}gtDq|U%mYq(wa`_RA^Leqj%cFfeOM6kcbQk)_nBQXm$BIVGb_B|1-;C5tR~ii>7IsOiSnu@lvDBFh1vFG;^riZj3k6Q z4_8NSm3cemY&r^#mOAdPq=xh>*pYr+Ks8NA1Gk%cG<~n~Vy}!@Dmck|77Jc?q^fAu zcpgsi@Zg;tKuT1Yy|o^Xk?n0=*NC$_p1`99rU(h3u1v~=W?4E@mCA?9n#^=IMOfO= z8*3FuTZY6WbQ((;3~-vA)T0E)tw4=X!L3anWW4b^VS0S09kBtf0GhNZ>Bpw#E7yTO3>PF-R9k z&~+gh@FKp>bU@o1*W}~1HmZfUH}Dj%@J*1b>-KI?msq9|EV;RrXi<$e+$&kDBA5jc zFU&@C1HF3lRw9+T02iVXmYo;LGF=OG@P#r4O%Q#)2M<}n&oqfp&ucHyEC@-R66kx0 zcqm?!bbry~@bGXSRKmuFmJ4Z^p3zncv4fnzvXmoqX>RL=by2hUC8M^QUq7}cEl|VZ zqP2jQWDLet`T}|}jg2rG&2%qu<2Um_}DLJ{gAx@JAkhLaX4~BTIPbK(kQ`I2p* z3U-vTPq>8u=#VD`aF=hr?fIJnz#+;x_R97?S$}bKbjU=jqX{l)UYk$eReoT}>rlhB`OiYtP9;iTiu74QU+i!0p7r!b(u zC%`v=EKBYNe&C1#zFmPib$_o!1(#5aWZpsBZkTTYb{bj!AI1|9&#W?hO&W+$5@xjn zbBBfrb6SR9RC~sF9$WNY986sOOlW_zMn4iH;e$U3d`un#{+EIFm>~Kh&MZ_oFX3tu z{S9Z&j}JzZBe1VRNoZK`Uy#jhvJj{s#2k=R#V_ ziqBd7eFmCB{P`ptO90Ixx}L(VB)Pmal=B@fBsSXeG^U&#+Aw>PvK#Z@<+B~<{Iu(< z@irB4x6Ih**g;;}_;=TDxo(Prqq~iPLMWdD-8b`5SNZx%Vv2biPp*AgF^9#S*-Ji) z_TCnhfmnelUrl&Dksh2u<6htUB#w4-22{eFsNQx!D6SpLs@M~Ij*&9ji2i3KUYc1e zei)8t2q5fm+1BcfEK}e`Tp-*{z@Cz_2ne=(Jh@48Zv4L@8 ztppdV2y4dlZF8FQTiZ{R(6>!GCKUl#-c~2wY+PGRQiMLR)EEy_u5_w&l$NHE7Q&DA z(gH;dumP_(WQA7v3O>bOaB;q~b(JK5#k!Rp>DE|~(EWGyWu|^W86WrOvTwsVGjjbj z+&>=qyfC_spS2Plf?Q0f0eti0!$U-|&I^bg4v$`(P13*F-&jG?cL4b90?&7&k&vPO z)9q_d`nxQgH^k?SCw#mtt|5%oEu4fETpT# z)+*?W<)~ppN_LGQ%$@M~Ew++W8gAIT)O(8m@4CIDQW-9^Y8ynd>m_GU_3Gwi^7ZX| z=Im@SsZcTq!?Z{kbGHo}wHKRk7QRQ5=ji>T39KWKLnh*fI!$TYW!W@m`BeUN4jf)^M)`Xdl zpl?U>ISS-3FP7;7%}fWzX?_gLa(V0E7{zH&cIJ4Z6DSTcGT30}4?1=Ld5pIL@3hfJ zHlxyz2_~OUQ8VY!=x^m$L-6(rF`QgXVF`|>b6ZmHSd%eEEgQf*3rV;$k zJf%?E$pDoH$c$DZI$3lh^%i#3X`fpI>a#{|%^E%+x5)GG0wI}tSLyY|Xt=jt`9%O~ z-EY&l{nu>q>~~|$$F4Jyx+>|S%uvEw!V;|*RWFRFkNZ12(!O<_ZO!xp320nKd4{;IohHlDXjkX|0? z!N0wNct^jG$_6JKZg2(ZAY{+{+F&QDuurZ1klupmJT#ff4=gsc+q9dKi^bbLB;-qI zBzH{#RH6qj=zGUU+~)BFHIvMlzx2?vU*vW(NCcKt@CwCbr6gs>tbPY#EsopZbfqCK z!~&jW%K6tOPO%g_un$7m(kN3>F=FTjbL>Y#HIrd9F0DbDTFTx?we%vS=>7cJA>>3{ zrL$vTgUoY|ZV&f|yL9c$FdzGGu#bmb=o1hWZC1DoyYl*d;%Kqdc`QJcH9+;#UEG1` zDzGam{{laNg9=RZ=*q1mCs<%p&`BZ2yg|wxS;H4;*}Qb1_j~ET&12vQyh6^Yv_hc=WK6 z6+?EZKr84^lB86rWZtkgN8S!SuZL+8(>FbN6O)B>bIo~7c~bzBd<=ZKz}OfAzq3<$ zDM2PD>0Y7jXad=5;S9psR=CTsnPo{*W&3Sek4T~bIZh?*^cp-K=J*+< ztb!HHwa3>u|IOKRyb{u{cPa)MIZ{6jYHhz4$q%+5}RXBRr`J37m9qt_q10C zz!G)j#q!|W<$u#4He4T8b8KM-k0m>&d$0HFf4%>{I1H4Do31wM`NaFD7^@35Z5^S_ z>Aqp)YB8)(2l1jU@j15wuoR^rbWTRUSY9ibX(2uN*%{aNY`TwX*cMY4Yu#4$Eu1|e z?;lNfr~AeG_h4_*A5X998(=YZ{FV71yj7cHq1*$UOboK%8t6)6wF(Mg**+iRAj-&# z)QrAC1n#;~EP8N|#{5DI7JVRsYfX}jA0rAxe}eFb)jl=EeOPz+1=I9?sb<(yW;^wJpR z=9p1vW0iRtTVNjOx1F}3b&hV}d5Box}NE$ay`ZI+ZU z3@aCpq80(ySMGm%0z!TIuB=`bPL)>|K>LG0^MNh@w3wu;9y*bqiF%Hoq^6 zUf&kYLU}d%m)AS>5&wb!qA#EL%l5y6Px`&pfMd*A-!CI@|;QJ z?LkX`pdl(h3}9_0^b6b{_15iilKbgOp>l26cI-O4S4j2^n%yQ~TMw~6cvW5lW8yS9 z2TPZyvIBBI6#DDvjZS!z=yEF4z=EJxA5V`f>J%(b22JhX!A}~7n76)ObZOhu_HucP z>+~U7-i+Fec?^ovGh-1AN}Vc6Gd#5DB`;pQ zKRp_Keeog;FQu~sF?Hk~QACl~a3FkuuM!>`p#0iRdOi&az9PMl{rBB3f=P%jVYYG9 zj%DhVLwW!==8Yz9FCh}t+jiVM58ZTB;FoYIfCB&`DrcDT)dH69R;zr^1*Z3XVv#{iTS!W&~EYv4rb!i;bP`NOhY zbYouA8*9z+GhCT4og176UipI4io1#E#=A=RU0o;HK*>I}X`2Os(0Ov>QH>;C<{_l( zkxcB1;rzkt$qyC`(ceXB*l5JJ)9bz7rAvyU+jtU83M{5|UX~6PBCtRCS@mj-{=Z@>N`|pi@`4wBn47^UYTC|Ss?5`urfXajc z*Bircj}8ux-lR_FMe*65_TUa1?9Abc4jsg}iD?lDB2 z9XX26E7a9%+ksR!CK<;OW3S--QoH!$X8*v%F95PZ{T%gh>?OKeX(iw;)@~H_{gtDA zI-Ty1hLhx%rT_$VV)^I574vU`9~9#LwRHO~5zobR=rjbq2Z9YnYFoer^(h~K{&GM` zR5Cf<-v=psGn$j?eXBDIGT>S-8Ngw}{|cpB)|oa;oEVJEkCfY!ZaW=j!?`wWo-J)- zGC}l;WLB<)C9B!#=E#yH$h5`eS)2NjJJpzpQ}uyg>LW&gH0$eCW(2<$9p1C!HAd&L z`i}Tt8lqOb9V?^yppC&QKvCzEwTnVj;dSCbj2QV^IbmLzL{8k7mdsp>l=B1Tl>;WW*RDf-2RQ`BpmbEQ;qF z*D9#lT)|mmbp`cneDr0zTX_TI#Fv>|#Cf;fmvRrtm8{;%Wv#eSoE(ge^|s9!DCX)9q*1bw+n<*uY%wOd8M1j+x{ zl%8l_NwpBL`iYSEPe(YIFokRJnQBvt#FckOxuEw}6;jZ%&{8a}t+(L8OCC$)Nt)s3 zqu~s(czhwr6+zEyYE30Lk$w5HvGu`(EW_HbLc|x5sw7;{|HN6~V8*@eO(ZIHgf{<_ z&MTl9`gWN*cITy)Mh0-VaPqtYCVLAn00~v={i%2JT6ZCAA-C?p=;Qg{(_8>$PC@>u zr>d>2gZk@id~bXj{TTGgw#cr?kCS~8ysdMdY}E)zQrRCW-Kk~86|knurSk(z zcSbr!r)MUD8Q5%3B3V23#71=4S3U#HZH3||%fYc`Eh3nL+Mf$7OOLIPd0Kehx_@`;{?_CFat!+jVBI@DByTg=L%M?( zFyGVQ9_L*^`~M)Qo4Gz@KiQ#M#?l-Ne;FSfgE>?p0wbn8j-5-2 z<~Ur27HeBbKM+bPV3cA#4ULV`-0uift;8HC$!AG>Bj3R^*426Z-_qi(SHwb;8uyr*szKYtcox=ac7(LxuFz<-L^ChRUV2~T^&SJUwx7*uee zPe(6?@Z%MgHC;ZSLfx7SqCY&)AK^QpyRUO7i;okCHY;4+H6yorw~_fSoqa6Bx5M0d zv83UY^w86%l-n+Aq_lnpj^Pfr;UUH2vKL*fsvH~N4?^SMT6a&U<9_y!711YAqT+7p z#_I2<&w+s(bUs6kh{5$T*O*rso_ZVeF0wS2Nf?x|YOXo;`Op)`Nl%+lD6_#BIvXT3 z=vn0&qM@eb2T)I@M`9I)fBtB+S3FP}lvH=Qm53(lxt#8s`|tKteDqZ~0p*EQ2Feyr z2R2C15nZB}%ME_6I6TS=AGOwH#0frSi5N2li$ zJ~@&RTLF3RWB39KFrCg9cpIL>kUGR4SY3(fMckssTHW<2W_4P};O*RylcbmMHbO?k zvAE1J>4Z{g%CtQi-oT-B<6!&itjUtYfo-QCqcplZRDIoeDAe@FY0e*_bS)l{d0jICfI z#1ok1o5phxD_vUHj%D=|y3#}Ws4LU-JK4d>QScOUP^tT8ZHJ@%)jb3CyeYS9(m(oyJFz9L)xf<)%r)(mwj-!86Zl z77ac}*6=GEPA4%W_^b;TN*A>H$o$c^bk{so>&KSRDs*mH?q1SO3w%bx?E$mx4T7&U zCbE9>BwyPA`^HA+bBc-i|JD`&||#> z-Jp+V^4RLd)&S9Z60+O|A5&c*Z|jg^uigGa%&~u@THd3^$%isGc$3763Lh=xb+zK& zD2n_TnimImPA$UM={51im*`cA1*-}kO^@Cjj{0*Xutzq=wYHJgHc05N^Pd}1Dg=Rj z`1}R``Esp{npoo)6*P_X;bA2SXQmQ7Z@@oJBoReQ^g@o%{K|&Awh6r(&j~yDozuo{ z3%tP0P>K;$Uf09G>)m&TKxCp^k&4mE>)K{&`~pxiy;|2frX_gtiS0|5WF=2z4l;Md zMMx!VUAiz9z5^O1u_b5bggEU`A^+tjQ0~Q`&WS4@>%6m%)hD2ns3;E99|kxR@R}6| zqyS9L79CORv5yw%%| zW-kJ`Z-#cLjuI+`~@XArZ{L0?yw2125;t2#w#x3o_k*aqaC zSKj$zviF{#W~`faqX#F_LgSZ+NWM1&i>cKx+}aA%7-?vo@|3TqvzJT@=HyGGP0Tba z7SLu3|>rxFvPpW*csAAX{)WUgN|wg{hD5Cd)I(}N@nN5_vrdqoh!lze1N z^XqtFFr2+%kGn69Cokp0@yveVhlfN{{=5g*WB(gJ+MG*gnE5{60^2Z}NjorXlq%#i z5+3YL5BMCPo-+(hKSY119xy^$cE9*>u2AtD?vEag|1NJ!!f7^>)yiMiTajPL_wd8f z@TI)Vzt(Y?-w`6N_mML}UPL;4|9c0{$!v?C9x0e;+m3!#V9{&#>Q%Km zC#iEj9al4R&lB>TIPES2ba4DQj{T zad&OL90x3RI?2&Pme-dKFIL1O;XSzfsOnkY6TS1X=wn%86`Dv!6YDJ)UGhp{Taa(o zOquUO>&&sGi+=9`1`@40AXXKmzhnQnB` z!t0;aDe=8VUMwVvA|-A=3C#sQJ`g7fWO^rnc&J<)Nr9&v26 zXBbMo>dC9hqU^DN%pf|;D(&~LE0_IfhBh0}ElbXc)F;rkh+y+{5+t;-S(UPGjTHAc zJ6~<|+Fbyy(Q8Va-$6+qDcbf1TpJL!fr7#&F!vQ=kL7s5`*(hj- zl-h!(GH@B!7lOs+QqPs0pk#`ZJtxEN%tt%hcB08Qs0qs78Bw#Xlp2a6-i+njwF1O- z;_dTmBjEHUW%SYs9y(Heu!SpZF~OZ;D2?+5WI(P;z6|%f?2> zz6O+)-He;9+-fZ|bsu-!&~|&YXM1W)(Lwm6J=D#rT*76Jv4=?k7bBfs38xkj<{QMt za}5_DD!@yM-KqjEsY(+xZ*TLs5xb>IP~Ed^Vt6Rt74YLO^bFpf2m~-)zg!;l8{(CM zs_VxG$5gC%To_t?`*c9|AiyKa%KM8`-! zVEmt39a2{%esw6mGO3JvO&;uRAmDZ#J7itkQ(Vq8x1@l;6qSG_Egh%6N}WJu9cI1L zKO95V^AA#ai~WQ51@$v$J%XyPV^8ed{M0FsRVLb=33KC8W#U+mk90Yl{(cm#Dpg0W zjP6v!B51P2J4%)LokUHV_2~m_Pa#o37dk_F2dsW8yGX`%D%NYujevh)K5EDAe7*)IjmU$`*>64=+Yu+YnKmRaha~mgfl9 zZiR6FVyMd9b6VBhP@UVFwuaMpXjPL!bsDSL6B@hGB;hP9TakzY*Ai1%QCz!oh6

re$F)St^8OeU!t@QQVa=~084F_?`sfjhYihV8;_-2c{X;?~3FbgQI=}gr%W(~S1 z5h8gcj5f3RCfaB zzd%Ki(SMrJC7PSr(- zA5*QumUK@3o(kwpVr|JUx|*)72+Ac^FqRKa!CG2a?3Gr;ZF4WqUmQPsHg??#{>0-s zgHd1;hGSUjX^6Qs&T{9@Xbv;(=09N>hLu)ZpLTUh-e%X@yw927HpL7#TrcP<8z0+P z7h0DfmF`_&R4Z4YS_;D!@T$8IppBi$4(oFWor?pU{&fnpEd@1^2dG5NTL`=q*^~k} z1ho+)2g_KKY-39On=DooFejEt*ko`UGkQ#vb@~!jm++_F&1{Lxy+@Uw3_?;PP?K^Z7J%43*`jN z-9ZS};VhM?o)}Q9n-K8!Xv0OtgvX|wy>-K6)iCfwJ4 z&YQZJW6;~t`?*+apI3CjM>NFc)R1SpZt7}H`(MwzkJVsLgr!7p zTW-QiHEUNC{L!OJVE7uuo2)=%9Dj9JakXh2t`8%=y(nQE!{mcrTQ+FkMK%FDA2&mHh0*i57oLuuU>QMl zNOGLNCKPFhS3Z2RH@=5?L#nwiVAZ9HQ?*VUB5@YQ(ctnwpdbs5f+EZGDi4nsWC%0c zell^e>GzY-tD-!bqOwfyYVp5@6I|(eQe6G~)2(7_>kIjR@%@wA=QEsL>%&6sSW$cx z$*bSMo|hg6t!=Y8#F|&KHX!T|^~8e^q0If^QG!j<#=I2qZhta;*}GJ1Lc`{Z4ywrP zzYIIF{Fpt|KnbY_ykzsi#TV1*k75YoYceHx?S&a@$Z0GkBNP}6=(4|fbst}#ea9No z^c`+z)9IqmEz}v>tY5!1czl9Y)xsP0N{BY)pc>ww#Q`Yq_+m`f5xqI-(F6XBvQE4! zoOJ;U-jt3Fqt^%4v_tfK0T&r`2`hK30#SlTi+OZtoQPnhe-ZIGJ6190icx7@<_>Ak zWUV;caM$<%uVovgGd7agV|ZyG@gZ%za`#;zL~8mdGs98-@K)F+?<^a+%ML6Y33Ndy z^9HmR#5a@-41|$q0rM#CkPaM({a~X53XeB|6T@d9?!7ttFkX^{Jtk1CW7>vvfMyuv zgS@nmkWsNz2R!j7Sk?AyHl6kEe1HG;?)IZc4<7A4+5XQbL7_riqid<%JEV{mAOqU>vz;@} zfSh@AbAk}ctCiyDvt>eI-E|ImT%`^Za=MUY9v?1Er8 z;n|tolpR-T$?KF!G1B2tz1f>HqNN4Zi4fMpyT&+4QnPGIT?EL=EudN$5cD(tb9IX` z$sjDa)gC)2wLU0o1w?sF_6{<_KEp3tburtA$F`mb>u>eY5+&MlHzO2WkVe{5CdKQX zhWe!}(5M|uCaHyClk&NL%uu?3bGcmnt_hR6jC7n#p#giSu;ek)XgDNl{Q?>FcA?@i z3iiSlQBG1N1Lcw6Zk$BDW0zz28~7MfHe8;SDqjO`A~LNaLnq)WX8b1c*Riji?L)BE z%q5>Cvwl#=2jys3sZJaMG2g)GJBA@0G{Kp9)=)tU0m`Xq9s9i1dKmbx|L3>_o|s+i zQhz$>ZS0Rn`#%C1cl#>U^biP)>X)~f(YwERGQBsNFPaE>OAA`COeTo0-aB=J@--U) zO7!rdm84rX>-^D%Ycfd6910pPkG$tR^RKm9uH=~l**BGXtj;x+4}%LM0Hnr-i5MVb zK}2G2GNv2My0(26z>Jj_w~!SO5Fs?TX3tZ+vZPXhqBE-vBnXzxBUB9muo_?l9Rh*D zX6=_qoNK8H@`O|jfC&oLN9m>g^2KzFG6Dn5AQBn{71qWQvkbFGl;t z-tlOBFi#Q#?^D_i&_F zN8%Z2v4?&$czd$3z&+DY7qP@;7b{_VwH7STpNzI;o7SL+Yb!#&jt=T2M-#i@IqryK zkPLU75h!ZoCl#WYhIa(YJ z=Rcwck>0+(d;c2|-~3>N|9D#y2D2^-=|pK0wQEp2605%nv6@q|6*`E>!E&Jwdz^6M zs?d}6Yzn{F93I|!^yKcXd(~+;cwmIZ@oZwkRVI8|FD)y+T-f|vwyxMPlm31C6xEFM z$}(6W4hwH2is&>r!3Y4#d;-dhOZOnX6pzbft=xGClfta{ZnXbmc>D^+DxU2A zxQyE;j`(~3P=D|553kq@^DE=wf1hmnZY0 z0{Jqwh|rp|a>nS+IHcS(cyXL@J*L!N((8`#yqKypm$L^j36n7*2^OJ}xNug3 z)QWlv_+(bI##OzR3yQd*0Abfev{l9#tjT-Hok;H!gNU6fQoMz_tny!kF~KzE@VE+3 z3)ymgu9hTJa5$%_iR3gn7NEMPYXXDN$zBZG(oXx*B?$F8>o<~{ul{7XB3Ey&*%)1g z`30XtzZc4OTeovf-rJZ{jr(GZRtD_H2=rQ;{T9Du{P;h%)uiHk`DS=BmT{qMS(Y7K z**C*kSv$RS%xZMhOEP?#nfJ{N^(vQ7p@tI7y3>oaE8j7!#BAK=oX z#mOKGgia&T3LZ3Nuf%1Ya4E=@7%cW?5=ztm<5Q*_F)I&;$g;--R3C`$VicGnAlS{P z@DFK-i%f`gT3a~J()yLu)i8be$)vO-gg}(wJ)LtTA&mA%uvZ0rk713k;wt&snYrp2 z^i97>Bv##=SyD5ftfWWsED&;ptE;e8To1R#sa=aiu?Dm5%8l#f)&4_=2C2IpXW$&( zEpfP}10dLC3lBhuEi<#*JF$q@_BoqVmugAYhdY#VRy0JpiOWUiFv=9l9sBXA6Twb? z>Ss5+NIw0^aeFNseY_w0mAMc2Nf-uo^|Gy%=b)-Ic-e* ze%m&AiQXAAyVL`dyUvxJIz-(#$v)hnAQ0G0`%+TW?pToDd{EI2!y?%3Fu48wqcgb- z!W>9{91tZ|YV< zmsi<>k&cuoqs$YP)rXS_m=#gl%IXcrQf`43z4@XX>Wz8vTQVO7Oy&e!n&wMg$7&co zuC5#Xx~TYtdp3zL8NoA+>31srbAVDPQ0JiH0@SCFav^vi=#JXqL-h-yd`AB10z!}V zUoM@grFFf=nCp>pP75xovy*b&IMN*>ly8NeKf3$v-=3Vo5quV^-k^7W{w9hWL$If< zq&?aG4oWJh`}(7e)0U$ zpDcg1jQujZP1XIZV)SWw7lAp5(Gl@rh?)RHtYSQHlO?P}`XuHjE5bTWpJ4AArw7#q zst3AwHa?!e$a@$a9-k1%b!M@C{+W4lyATp=Ul10= zOKf~w5H+ZqE{uiBZ8I9^7EdRu^mKLrIEaElXQefGnH9vRuw!(T)xkHv#w@eNw)H%MlKL zq{NJXnovLR%YbQ~x>hsd4;_?59NTIUwO|%6cD_MO-$8MEI@?3Q-n4EHpW`~_{rP;8 z5sp93QIYKMitQf2cay5YILc9UA>@yg1 z@sj2TNR56twrjh68>H=Wqcv3Ci*}m&Gy}pTRwU#lf`H$MtPgn-6=I5m6XMnE<$+np zcMKJ7{`^`!sg4?E1`QZ-r8`n4y(O$DLVRv&=3+D`9@~W>f<~l9O0;M<5@MATCqtv= zJY%&sFI>m->K|BmD4Tjw2A+-%QSebXgabXuGaWym+}H;YPp9J+nk%8ihU3kFo9lG) zagzii8^3Fv{(glDHy5f})zU~F2Zm&y$>!T-H-PkX>!&GjZ+|*pfH)!KYM&*P86RMg zTSRyG#SRcb$^>oY0|l7btJJ^61L2T=C{mQk!FOO(peHYYn-XNi7&z;b5W}n9HF8X&svFbl2vdq_`52H|w~%9-OWL>w zPvDRN!8p(q{QlYlDbGyLV11nvPBThYPk(X z3uGNlkC17BknC(YxJW6VrBUm4nAjW@-ANWS=ZpA%uO@*C+J@S*Le*lmP# z1CAlQ+p&oE<4s19bEh$-#q|F1;U1#?`S+y)xhbj81tg;0Xs*nr=Vy`~3U)tM{lN!L z&D|W=CVJn&pFM(8Wp~8*3xLIfT49$702)N4FA$C~m_vX9 zHzD3S5X)S9gdqE`Kqn^?6Yq{!MDNs>aV>M@WeGm1m|>Jfn?{Ram5iAZy3C6>gYypT~z9XWueM6)g-V#KOte#PJ+=T7Z1e7wk5$=<~Q4Z zbu@zTY~YfuIk7f&>~KvfC+pX2sQxR8feAOvPXCLl7T&&V;T9vHHusHS!xcPcTHigR zM_3D=A)Bp}Lg~7rmF{V^UE1dgfzps}dyzU>hrP zFwf%!E{B*~of@jRFUt*@(IsRw?I${{fH_0IP+Z^y26K~`+0S#Pa6w7?@#PSAl8VNx z-BC>7sa86~>Dt8wL`mxE)q<{g=d97%vA8Ef&^ zn?|dD`6W%NXnXT747+A03S-RNsDPwFI65@qlH@xET6*t6tJ&BoKs7naQ4ZK5d7%Mv z8n4|1vI?D#&G6k!^f2oPGZNUwKR8oRMqVYWWQ_C5$c)T$Ir(ZKA&G*wuHBefnp()y zm{1xqER%JpejqjymHr_ZyabFOKmb-65Ge8}Dgp?LgCTAR6~(kTf+j-;Dob~f55_l- zL!gkIZ2$!i-%FmlkI}yCqZ$!z-*fK+N6fEFc&S153hYmX+bSr@+jS6dPKb zJfaGRvnO~F3YTCB8l)pk5mh)H&R1cb?_&W;L~FdLN~=ve{Y?BpTopvK>1K`~2LuN!F4 zK$2biCEHIfz0$GD$3BtT`Q~tNGvBP*dqF&MS&CEkk#nG^fQ8Z~rHzeFL1O*}ros#_ zY?NEPA$HU9hg-Xm)ijMXL)(ft+ttM;wlv7#I6sym3#~N$j2^DKS7(@DHcBU6>+%B- zO=krLDSih;q&EaV@Pd5C?>0cZWt_4AZFv z=Tcc|NgGkwRvx0jeSp$5PbIy1!x0Hi~tbQ8?C=1!qc^fW@xd2yR%Kqhl-I{)Wyz%W8%9 zRbF(MCDl=2$e~tf9Zd2DM`{)`k4H95l&b=0c7kL8*{={Zv14%v0h$h0qBlJO;_8D= zi+)Cvo1MKUaPFW%lXGufIHxre0o^cIqat81Fb`BvP}d(bI9KCpY)A#fF`FeI&V4ud zO;W8<<2s;+9f^(Hc(elOC*OI}C#1HUu)RPD^-H^$0c>OOYtU+kdH-DJ!j`T=^yIZX zp46vB<@gUB5t+}%qwX>VK`T=yIkluEn(fyt4M1_uo6#oD?}>~i@|49w!nrq<`fRu< z$)vUnk}^|yEZ+v`ZOC}_BQ-;&;-F9JoKOC#o@+N@275}j=833Iu&h?^}BQL z?n4O*@%gq&09^oeSRPK{p;5zuiPemmBiIf4;y=dI=@@`TM}^Nii_V7b4u@(vJA}(s zyV-~PRx@B|I)l+6+|@P!u>^jNYG6X_d-Uyr12)IZrB!@=fms9`V^5?;Q*{J>WrC5qF0#PT>)btqZJ>UIX-4UYzq z%~tLo4mWWPIMUO^wKyE(7W(H`p-1CL*UykCDNzO@wlb^%u3Ug8zad|eA21W(L&7{@ux$xOc!$!cSUH$K z0X_W)u_6vbLD54BNCb1o5mW_L2Li&p{UY*y0_!-SuT~(xK7+#h&8E`jPbU4V zJ~pDx-TcG|OqU%zXBn##jO5<*dX!>(I`hSP@$cwb~;8X~W@lqgqk&Y*nxb zc!3Gf#EsB4tw@yZun*3Os-EIP(n6WhtsGS?S;AcFwXmQ>eIYs$D_7dFnBhbb8D?lB z{|XGDLGdl_qJjvBT@P7f)jbF+ioOH7DDU{Gp##VeHk#llCd|@0y71;yvxe14p+$mJ zNnX>QL=u)?vZf|N>l^Vrs6cJK=$g`D&jwVsMF0W#-6nPf8eqG{!{}49u9KJqCyFrK zg8WL_I#Z~2elz+;7rH^Yy4odT=>=tV35ya!su1t;7Q}$SL4B6Jw1VhCt`@LIKA7`k zl^-)P%7^mLb<~7&g#4#vW4YP-z_4_$5`|fXLus3qWp$fY9DgDHG0>&ge!=sk_;;`? zSX09S-d0ir>V@1|7dMlDP00PHpGYw>yPi%5N-iVUPRWVDSUwKMQm2^KKK87gR>sd& zf|VM!F*>Rh0NDl~y&i+*fD(GOxBAZp`rk8*Xw zV^Sn(aCK<|)y+XSTUuUQt)+E=YQ))UZ1C%Ac42*?$Z*zIMqistuN8R8cEE{YqFo=R zc)2e61F`{{DuqEczEP}~l>Cjth(8QI!Xr3uvB3y13xWWYB%$)t_jBSiku8kGn9G?R zTj*9bW<2^+!zsMaFqulvgR1J(M!y>j83$@r$}rVt8-|PUbK=AfqC-)92b`Zc@p*sM))~@)4l+;90So z8e&t+=Tp?QzGHG<`e`*A*h>_2j0uGb2it4cy#uk3`OTf({^$UzHG(*v2A9xKW?wkn zpt|lXG;|f#xd!a{t0-x6j0-0YI(g=YxgO+nE>WrIXZ~L(6J9RqCW>RWaa}R-Q9%$S zfOYB?cucbKy}DeSBpA%>d^`LlPk2TlcAW|0NOfh2P*-Q&`6$-;$m~ns=W$#knm@11k=G$KRK23+^ zSeNvK&9w~_wS()O-zz82!7LcET3eJKg>xkiS=}%S9@!>oWi3Rpm#@&@=GB^FB$sy zBH-EUE^fTwZ@H5xz2DO-WE|<^u1akqWuRJ%FFtHQun6d40JK7XX`9KWWLgD$&zE)kzu4Jfmh0BZ{(z&4Q=LVxIzg<>mzCCPGVIW z&Z;6xQOCTXVx<AnLHy_i$NKF*wXj+aaSU2WpUPK5lbcF1|p}I5|WPcup+5C=`tgkW?6)hjOs^AD22x$ zRAU)5zM;KCOAwU_EbGzU^G={7z)hfK@O)kV*|d_h8AQ}_at;>&cU??`{6e`^z16nw znVi^qs|gJ!8ua#ye&8;(*Dz3FV-bQvH6R_JovHsCyksRaozE_7wahk$?3Wp#hEkh+ zPX>u~>#)Hr0aF>x1a0OB8>k0&FX)(r9St{Ji4V(!yLaW4uux>AK)S(fpCLM~syK7u zDBh?$n(48ocDBnzkG5|;`gYa&G~TySwhPctX_T&+lTUGg2_86Bcrj?nl+lt8d*ule zu%UrTB}yP@pb2Vmh^ZqWBYtU@O(3OEdTm5KF?a)awX%pXgQzrEhNUhJ4<`N5^a_98 zji2Y|yF;&L>O8l4C)NkV_*d5eRE}K<-OhtncVv6>0*sqiHEu=L&C;dnCjBGd5rdsO6ysaDPHJ#Enc*A!`q#L-K|M*$%) z-xP>hVPyn+ui%ZDUlw@rPtX!^sWsmR5n*bBy^M`r^4U&IoA#SJQmp_RDNM*Sw3TDH4OGcM)lZn{;|QKi@vr>ME+FFT!b&+xE_CDO;5ih3!EJk&zUFej-YT z$MB%iVCF|r?4;X31OZco-OHCR`zuG;1$IPWod$NakeD?|+8pLVmRCf{*df9O8#GOS z-}T>H23*5rb-jPFCM%nKIsjG)%IJ>J;*{HA^lWPx4bv{OKHePd(xGzdHRZiF!wf+y zv}-D)3)EvS)+xT}m;&omQab|pNND1sVxu^jgkp7G#r%W&4biO$H0SG_vngb*65 zZ6%(R-X+4LLfdJ769EaQ3tXBjp43CxB=++be#Tpf>{vX81G|*YMD`8RZTpEM=O#(N zmC@*2f#2yNO6zI#Ci|o>1P{~fS974moKnL;1UO)HD(#%X>w_hyKD0rI2U_v1>b=I} zLsVN5cRJYZ%t5AL4hJe&Fku8`0<*iAH5|QVjMf^3(Vw|pptov*Ap+---vUY0RNoY| z(OIJ~`s%7xNa&}Cyi$$A=&h?(VHCuGntDo&!sv^6b%>eHL-zBag@`wyL`8r!FBN#7 ziuS73r|z_z9Cj(#WLB$CgJh_(lGC@Gh^a~VHF^Y%I>YURiSyolXEh3&>x)G}tMP~) zy;}MA8ijAUMxh^0)F||PU=LxMMf_Hk2Lhnf6PJ^8gS=*v; zY9T4O6Rm>N1yn6uv6!D1>|r?{S7V(#1?GHZ%YUD02m0P-L@&*^%kBj=Qfmj6uTVa7 zj++(;jXnvp?91rcBH^0Z2#?+a(dAu!;_`^ot4vz zwuneUtlyGydj6(a0yHt!OSdJ#ma?EDg;t((A)b~H#`S0kV*L$rwn5z+uS!Q@a@CS^ zQ3Db?>eb|6Z%DP=e1%{5T3unNE-`^YS4XiQsk}*a6%jxtVK}v~oWRe%e<)9BvjWW7 zw`}X9K;9QpBPsvI=YV$p)jM5P7u2p5Fru6D^9OCR)>uxl^tr5d&ud4s}ukc9g3*VoYi`>n22f) zHmz3GVIZOE(Itb|7(}l=hIbsKj<_j}$A1C_r{A#T_ORnS=5m8gSxpPQZWXd_vqSQ!Bu`6&2@PIZ7pBQLv{N?Dcya|`DS=k6&j{BD@cQq70b5(s%fhws5UF60}1kmb}c zJW}`Ieov20R&ED!WTB&acoYjn37??8w`l))jm#D%7kO<0(f{#0=G~nphI@#x3(`yL zJtj|miv9^HFtzZ+=Zc)CUYDKp+wwj(aL-oLX@gu}JYL?Csj&_;5eK-#r_0-=3UUd9 zY|`=5@*bL_Hs8<9gOZF5NjZzkXVHP_xa^Oo&p{Q^ma0Kd3O`nDdycDA(fly#xR|=h zP>>?v2hMIh)I0kt59N_W&9$Z-gnOJr5mIBtaZBMAem zwc-Kz>u`7!DbycYp(8vVsCJLrIpl5vJek4Qhu{xb)yoC{MY`LBCgAzW;ofwNFPsgl zN2F>QIu+&n)0dN?gnIxUEBHx0<{A|!WS;{*VnC5HWaU|Z^Fl73@JUg4DaykmUYjV> zq*S4_iFQTQ(*W1vKFg4DmMGB*cb@|=Wh30affr+$&XTd9ZytOHh4p}I=GrXtJ|zG} zFKfuiU1py($g!*_qpd-VLA@)4m@7X}OvqlJ<024XJb(PAERWJ6y6g|cLE9ck5*cBY zlJ{0|!Z9o}hOwPv6t#C5(yA$>jLQ#kB|;)a_C7FNNRSPiXPT}=hq$<&oOecObe{w> zZ>JY77q{;{xWB#o_@Cc>{ovl?)9d`y5gv|X=0wQqs=>r8%WD_D4x%&+1ac{?8vCAE zcp*?idOkQtffY5QWCtjPg7RMc*ayKh2CiRXPq9D}19T39G0H|tMH+VMIU;&PpIP(s zezW<|rXTZEz493@EC|JN{^vq>x!AE#reCB4fgYRq-}ZledOq)Smr{8SgfU^q1wlyZ zY5mO#FY%jiYKBXG20xz(_5P7>?^j*u=L8AWBdxm7tPa}r)RN62IA*@BWrFOL1pa&{ zSgoLjg6w?|xSm+cGN~f@@wzf7%CTq_0`*)+?_jzw9-sc+^Z)@aX|k!?0Hqw`*%1l= zRGOzI=KQVR`%!J)CyBm~=%Gfdjjtbk^Uuh4sL+{m+~0pO8Xs`=A(OaJ;Up%+=7yX@ z@*%61jjXIT8RgOzV5{uvhy2-1a&EI@Z2b@L7wJ z%}P`+HRH3KdZ;de4{^S0@WZZ9{x#6MF|(LZrl`~q^Z=YsMX;p|GOef!JI})$WfH*| z$&63oj%=_3Yph^PE9}Zx>+#2Lwzsti9xi#mK#oZ)YH-cQiCzq>T>vX-%q)YoH_uiC zU<5v43TbbNfY!n*}MW3{*xOkSnvC z1YOLyg-ou)LY+susFNZrh1Muq69gG@GK|{`*B`y%OOO+lou??ZJwHNlIs34;PgEIF zmD45=2pnB^>h`$&Y=i@mB8-?UWPY2wxjtk1dFn|$YpFTj8r;R&L;zt;24MOG2m~LfkxO1^rOOO$5oV4lc8d-n?hMIR$SOA|IAB#ou9U zz|P+T%2^f(Z_kN*?OCU5h^o4PWYCY~4Tz^&rSl1>oqm(`lPWeFt%6x3o6-fV_vCwU zF&LKB4#hAq5MjJohJo4d0T=K-{a0X|QX&Vfu%CBeRNjyyHQH4Wr8=S}X(4;dbt%{H zy2p|xN(fnfy6Nv-GTi;){mTXZSvp)@D#!Zduy9wREU$sU3Juhhb*Fial0M_5H2Mw2 zXY@xt(tehye;G5D_ELiinY%C#vlmzl+BHm}|!$$X&_YDwpa!nwU_nT1DK`hz-no!2Fdfi|aBA5WuDfAFm#R)7qnOg%onefFjAE0s# z=hL~wgp2U-5S?NYnH6i9B%Khibxo&}u5Lmlmzrukf6C>7Y1t*@*gy!eC|9;3Jh63yoTBaR9JW^{y!%MOn2(;JaufZVgoaxT z({R^n09KHkHQ4!k0o~$P?xc^);TRhcb%e7FHghy|P&on{8&Onv#@^YAsU8Z+N zyJ?R(sX%&5t6g|Hrbo*M%howZ5@s3+@w-~ z$>Jo=4pX`-Jr+!t?Y6(Ktwjw1V)cG{Ej?5KrFr7o1Wwu-O}(@5Y;rn3&gj|_Q9Z%{pFgj<|FBi)8UeI?w2ca07$0>=tOBCr+7 zej7s5cozwh&sireDJ;`0$uFeMEzR6Pay|ppKn^phs~Fsu>(cw*-TKen$G7fm@7}%t zWc%CgN9R*|F2K`(`ugXR0eI?i8fS-TVRGG^c{#0=#w*gx6?$qXnJYA0gK9eSN7RHM zP0r+hHc)jzK)8E;LB`1HmMY(mTI>)GJ{ZmKn4i}~1|Suk@vZi>4ySB3rG~oMB^^7LbrYFUH_=@&5M!s;z*70JbgZyn-$8ga>Wbp7Vgab#Y-p9|owl2-OM`h_enE zBU{orF~DXa0Kc+8oPp~KFyCs4s!6dPzz7!vZ!Sj`9O?M<{80TKNVLATGm+}AHL$Z0 z!=oX^ofOiWwMH>lfU9n+9L>FL2TUk!q^**p^TwF;M0&;}C#R^>)1gy|y{TM089p}% z;yoc$fbqnI;8qIS3Qa?k@Xkp9-?_Yc9ziveEzcmHX05-6@b#In$o0h2B$>jb_!DGP zdjJTTFOK)_(C4?hz*#2{gKr=RUWi`uK9GbgO8ZP?ftw-f2){VKoaSa3&86AKckr;? z0-+rj*RB`Wwys`lI#1e21g*&0MQ9)FuSM;UNrk?_zg9o@v03gUKHJiH&xO|S!*Mg# z+}3iYGqNKra2#AY~7GyPRF4cxOV7fDX0 zMJ=&G^CIX!&k`Zb+J|VBCZGx(Re@IaLo*a;xoaAxnTbHf4xf9T*b#{snewaY{@Q6; z^(qU3#;sQ?fRG|QV=L*w#bd}_lDf>^*RxHV0u3jZ+5j-Er#LTYHTs2wm zV)z_<7gxt5nK@qMuE_7W)pB@*7i3v%fI5%TBGc_+hiy>eZuA71n+w#80}yJzG}tHK za!?;omj4e%6zO(%u7W9BcxNWJc%lk~ozBlbqz<~o+XAv%-Mv_ffMF~mgO^y3ZFB}z zt?ESzctW@lqsY$`loU9$EI6q>5^)|Ge>(CCIe#(Q0mU&@n!!VAsc(`BxJn9Oba!eh zps}ldBcITi2IILhK8d(bgujfS*S`dhrcrn_LA1|k!QAlH?7@EA7^Vyfa#YNY7H;QG zIuHX(iPrlIjYhzYUr1c)!(u&vx|(=hbn%w?k{sy&-0(2)AzJNIj96=^S1YGfmqr}vkdF5!d+=hA z(n8kU6R>*HVX&8^JFFHF0^~8U5MrAc&Dx@?i#ZTszMYlj0wMLr$%EN5z0erwmH+*s z_vII(Us(3~(!X8lBe#BGuRH&3%PNdP68N@&Op;PO=`ov=Ll|Q%^0@+_1l}^yppp)m zv3wAWBpb9%lhTRkU=X!-QbF+N)9Jz9Nx6~opt1KUEEaE$P-<OO_zu2*bXWhp2)9Pp)gf;+wxY~xE38d*1R>agm@#E%*3f{ZVSA&~ zWC3X^_>!oNsFkowJrIXe<{8dj2?|)%HA2B4MyQU~@NGC@bQ)@^n(SXySv!~>Zok^s zX9iiISiOpdiklSXLzKqMwOCNZ$~(M1q5eXv-OcyBRlI3O6x15SB@Im5a#x+!1#cR^ z+BF<_thqzH$|I0x$0If1O_$y+tt7k2Lqj>P_zUN&JMcajg>4&k^Uj1nx>dcE!+Cx0 zdL9;Y_x|qRZ{7QT+o7P9@5CVyWo^j26PbM~4(?eO73^zkxp94M^Rtav$643tL1$si zlwSqpbwf8OC1_dpyFP2}VQtpXa7DS8_nUD?xpa0mDD?1`{F=2>{L{XJy(_51b)^A* z6)0-TJ<+-j610N_88@kP4HAw?KY>_%j1)zh$CVrWaWQ=?)sPTq_S1B9fCSh1{1~Q( z$VMF~=>;@MIz?FO8FdOX*W=+cq_q{FYh{?w*)|~0!e6l=m5kVfh0v*`L$oAuPe26R z$1NbCABg0+9;4y$R{6~Ha#DRToS)R+fm`F%3Eo;8Ul5OE@p~7<66`9PB|O32I3H7Z zFCw69=gx$QwhQYp1aERGN2s7=g|K@UXW$9m^bAbFo7PFd3S1#rMY^lwjGSRewlk{4 zzN&w14Zt7QYRbjl?hKwx@5x2zXUMT#pdOsuq28Ry8dlHu03&RNbv0+g3f;qXkiuG= z11GG9GoXaEJOf5p%k>e$AP$O#V#Z&KO>xxgU;mD))u3u@QJ&H#f4N!I1FF~N5inmR zKp#WHKBh`THmJ1{af9Dlw{bD~95wGpM~hAGZIivtQ+|13>4SdJEBnv;YU+Wj#N{7+ zRj!OLQ4w*#uz!Vx-qt0U2Uspp9;#f>!)nAAaQwCEJX1z`B@-)`xd#c4nBD)*WzP0pU2(gfG(e?7%P0>j+??Rs+CuY{=n! zZ6?uByuTYBU5L*89;Bu*P~%Jhh&>RKDLxx|b0_ulMposv(XawOMgd9RMsu``a8G{M zyxKg;j1!4qPyB&nRshUv2xM^;@RhM#duM#bKvC3gWb)cind`Aq2PWP|DBl86g(&%( z3ORWmu2SYuq0{v*ofgWh6PB*p?H>*o`!DR4a^&3lwAL#I_0X1{qDp8+7>@xA=-rAP ztN)4ASVGZEB8edbxdrcFEqKmVBf)OMdN>FlOqmn9Y>F~c;$7|*>KBhuA{YxYcYLD% z49^+js#IR8_Y8%UrSdea5{lp1l+VQh*796D5C-|$w}8eO1r8RPIA@J3+dgz8n;(l> z&HWl+$NVepVQp+Cg4uFbEpA181f)a^g;lmfDXa!cFQEl3JzQ<+p^YfGcp{V`@29Ia zl`jw~gucSiG!3?>E=7O6%m_F60b%3Am1gq+B!U^BuTCwtrCghw1buZ zkO?lKDX8OTaT!?=GVmw_`wM78SgF4~+Q?oF+|t+55ncnKwfWlX1z$2{_w?E$x28-(N7jqCqt@3W-^^@PNb$lr%3s$vir!{ ztu43^b#N9vp2srmh|Tl{nI(;FS8J?eMO@HojeNxJW~WFuT%U-DiI&lycMGyVei~%a z4**62qFhp~va(!SZ7>Q&LhGX8mbP;I%*9OhWjc|x9=Mkg4mXs|WxBuK=|)Lc{EiyW zZEnZ;^w7lsnHBP$ek%Xdq)A>XT-@D`p^PeE9|dxKSz*tGZR#VLxSi$ds6XU3%n>nI znyWo5sXq8=sur%u+*kk)$0OY0av~)@5x%W{`{+y-#63n`+Bsvd0E`Cz#B_>Rydg-AsSK3p(-gkV=>?28z@T*Z#l$u)1xC? zW;4SPBFGUY;e4n=XkFAdQKW=Mv%?{7@5YrN`?!W@_63!(nB#Do3kJ1(E4qJ!di9*-6aOm6?hl<6wGeHH!lLeZBP zTw$eOe9!933tUdPKs7YZA4`{d5<}b@w7*DH(>4xk93%g-*x4KImE+B$>Gd1#ztksq3+m}+!2B)$(S>&ABX~b5?4y{2l*HRx*K~fR&3HIDj(`sqN zBvw@Sq_x!09M+*TEw`&|3-t7mEws*H5J$mqH_sRBuK8cwZpe67t;lGM# zVvE*s*QPpZw~iA$3mCn7kBctiY^)b%`!&-H@3RS`SBkATo7Rx6ra-GrsZeGRQZfB9 zErX`zGae-ERhhJPu5*3&4r^}2X#V1C2RmB(T+yQASUc@M_tBAa5gAt zSou{<$we$ch$?7J;KO@q` z2S=nJL8dJ>Q;kI&*hO2->8!!Z-aQQhD-((EY{06*(98Gn)7Sq?$OP$C@u54m21O=S4*>_jf`)2Ev1Pg2*S_^*WmpS|l6k(E0q*G7b}*xi{< zdx<~NxJ6;RKZH5zYEqG18cJFb_0+r?21P3L<)rGXcDhk< z>}x}So|cNWKb!7-{ULey^=}-!P9t~ncjODrhtFUe(Tc9HZbWoAm=nym{LOAe2cx>X zy}iBp>Bl!>jR(_Xy-~Q_AI(wR$3zwr-$rwqk0_m`P$k$-rZoE6=Tm>xL{pA3;Yz z9yHWST~|%5M53Emjom5(qT$iexloM9^te`qVn*Z06wah+Heu@IaBn(Z(PGnpsW$LY zID7ZzykRkywVe&7q-pQ5eDvW|!evVkq+MEf18g^RY5R7VJPpFM?aB})uh$@KEpU9;48}3awZUZ!o5&5r)eP7=3O0%vMzR-ccQd`kw*TecEOyoM@=4; zeoU+?JzJe)t>+7PpBYlNk~1Ct_t0XHXI~zyZR1ZZX{2kwO534l+$pv0ARqD=_JFKh zixIVRSOP3I{Wl|gzJwfzxPY@618g%y3bpTzQ|#m$d1FTB*BQno_P{Ieg zItzTH+kXB>Ut-$WhSNh)^m@tXDVXT1?%#IUnI5@_9(iotw3`Kg>CC~+Y46gQwD*wb!7T0!-Bv$C(wEvAtL%85Sm zx_DGBj%P@?qxl`qD6XWTw=KK9b}?1O242S@yp6bMc4H5pZOKgH*nH|><)6iF-}`9S zk$3cV@I4l1+}~K%zDb65mc8C8Ri_qpf2Pl}&Nao8S$`Ow$(<-SncR|W(X4;o=5nkX znZ9(3kL|h*`vs2f=p;8JxwKdv6lRdSX21vo^iKBhY3m%U#glx@N~`Qb*)$%panUSy z?%Yk{38}6CUFEf?dj2KlZ5s^cQm=_V7byc~ResT_;8)pzc|y$CcXnNM^R{a>ZOH4z z@idMjkS8E^E#ueKYv+!R=tg3lVHXzH=D!?`tw7uL{JXd<>P zq>jYPFV1DZC?)^J=@85m$&jNuE>FK6Fu3#u} zY(9EE0S;-W#a|Hb@g+;YfE33$rpR4+`9rDvVz+2Er`re%)mb!`xH>|Gx44N*o$lME zC6%ha+jZ;AET-nje)nG8v!b>wAog=PZo6l)6}cUU{8MnrTbzp9aXD~n^9#XipGyZ~ z`@l`K_J#t$8R8IaEYtwZXIjDj3V)iF%n-rVxIi##fJ#as1qQS6&R{UHuU{6u)c8w( zx`{8|;}`ajc2*}EXTT`r_>UHh@Rt&V40A;y3x&C{ln!Hl%y8mcq_qX|t2qOJ;+0N> zY)Se1P1H7fJ1A&{y;jFSYj8#cwAP*YcjMaUH$MO5(`%o9><90kg8tTgZH%*ab%d+1 z6m>e>9uE(XdiCOcml?LmSczMY9^Lxq?!E2%-#+=<*)YUnjG6$xmh`rDUf~V#fBUHQ z9Mi}&u!+POSA{oymc89=*$Hu?6{b2wHU+2CYX>h8*{q9B(DEM~p!`z+%Nln8R+@B^ zm|M#_Xi-L6z`q7Mr*aBt@Ww_m7hE*zCV+ODJk!=$Z(y0f)_h&;m`r4RNO!*Sli3;99t{jzw5q64VeGiSh`9#4PH z>%nj_DsC3?uD*oH;)~+5tR+-WcK-G7;BV!tym#~oIKbPweiyS>XWo@?_2Su>$)yv- zydb{Pu2RZxQqmZYz#_S}kkP}aQ@p@+g;M2Mc3dn^yz8*~BZUE+KqM6eafvS1pokaY zj_+o;ibGY3n2b`bi|7`79iteE-xk)t2Y|cgIMsHK2-;=IoHSHikJn@GcKgFQwW^*Q zz>3$Gi>?F!eeJ<=7&{JWuQ-`7}BpRUTUpLj9?=bjg~H zs9cpjAK$vOy=&%?DnF3kntEw_Q>XZe;ul|$89 z#>GElM9DxoEbbJ00va#29f(1L%`M4s7d)B$gkl8V+&_yo2>zSJ4qbH@cIdA${Zo)b zqcK~J`WqX*bpKRf)FzwFbn1=Gt))%6bF?awpdrFl52bzv` z{-Lq;X10m`d`0JXK7%A8y4&?t9V3?Zl~q>L$Cb*AE$7l`*6;Vd<&JINQ>8$a1I+MN z#fW+Fv$uO>UPs@?>|G6R(CxTukO=vv(+Pc=n0IRSW_0lNaMmU#Rt3K#NyWZY<;0p; ziB2;i@&H2Qjnjol9I&(5snv8Atjha_6PB%NiEqjnt#IRw^)h7ha$}Rum2j-#H(!cC8@BDr{H&&PoWe0U%;tI&KHwQ<2WOXd{zWQv>a(0mc2u#{GiVgC)L3$A za3EJgS#v=*>4LfrCuOZS)UQUY0?Pt)&n^hy$_yBq%U94`lW?9AM)dU4IKLK(lV;py zcyq+*QY(K=^adK7X^d-A90~Gp^%9>4pg=bqJqlMd69u|UC*|5SC{sK$Y^LUEbf8X3 z&VrbCCk@mbwp{WXprJ)a!1PCxpQb-TI)O|Algq&|lB#HIQFO<1k@323{EZGXi5`U> zLQtVHu;zWg(PcI}DgMBcv+(}3UG?h)KZQ{GemW&=5lG%Gtzn_hSmj%wHwtI-s`1PNiY#-qq|PUk8Z9(pd__OhHVNOsNG^yD*xTXKzNUvpsfp-ez4R zX@DL(M1{UNNW*R)o5+&#k0{;u+zfVi!WFgEHZ4;94e!Q@8R}qPW&v3XM3e6fPJ@IL zB8TT~)h%XANf_s{G8qF3&Gzp?SASKReyU!vGI6W4cg>G0QFuAK1oAtXGyU(qAancB zET2!|2zg_|)31z}De@ zS&!OO%$Ik9vbb2Ih?=AQAG4l9QfLY2KEkU>4m}-_$dhgAahb)AF;aY(m4V###?$t4 z?88Oq(}>&N*?QXF>+dsid$@D;=|M!{)R&aH~UGMX0DVsW@ko^1A{9VGJ~M&9*$YT8d61!UAX$f8;; z?2AJCiQh9JHl7h>SRfm5fbbn)AGJ*q!0pGpWSG33-e_Ko5WP1W%k-DEtvfyx?6t}o zBTp`8_N=tS5)k6il;ZbLK9JhQhPy(Nz%g^1SQqL#xg{8gU=H4cR~gq9fRodu=909w zQk19LE!pGN@qfe?DqOoC1e#CX{~?ynA)G$>Pub#F2{L-aTBc)Y^kja?9e8FJ$^+Je zVI6o0Dmfw1LzV?>5eEk&x@b`R-gqy#FfmmwY>3xM<`4pb`t2>g#tSnSte+^QG$uC9 znXZ!_JrW^;`JU_JCINgKZV%UFzbVV3H194FxZC&l-1AwZK2R|Y+b^;lk-qeZ= zjcsdhnkr*&CY6;DY>51#a*Uogqq?R%9&6;X-!(Pw>jS4Y@(!+=ozau?54@>xA?}szSm;`zx5?gu z_d5=+_~n;0L%vtw*5CiqH{DkGkYb&>Y?#&dL0cJ49oT$9wS^Sw`6N;{C4NL)U*hzGpv% zbqFvCwiDrGc{DpDZIAYl`LUr!1sc0HgqN~+ujTLhWHJ@W=gF}FwoUpBd;dIxb^a-L zQuG47Tp|C)46)ypv*%?@%S9|kVVv|1`I{Orvi35@nV=mZOo(7YwfBTBh}h-%LuHJlwUUYv+9MOn8T$`vt`S-e&C4xc3Vui*>5 z+J}k2Poy}D7s41M4FnUp*Rv^a+(8B_g)iCze4RI8em}s{M~f3xzML1M8}&s&e>Ix} znr5B)#{O*PhB(4%@Kv_whjLjeE-=;I_QWVCQso$FM!DRXwxUZ^A-hL%(u}O^=Xf2O z&fah~DOsnQ7=mkmXr}*!_5!&L34gJY0PrYpgNSar8}VPXxxsSR(MGBR)EXU?d&rWS zqg^xtGG>i*pcv=10d?kQ*zFT$|D!zV$x_ml^Svq1%&}$K=j}y*DQ;~2xy9e$3q};X z%h~zJDOAy_K>ChYV%~zgw zOBWtk@5E@scg(lMKY3YIbsFHnw40nD?obwm%V}4c4lG1^%GgQVXjC@MLmP6`KCpjg z6QJmEhLL^X=AsQAeWj2>LL||q{XH5_wJ-%b`;;*B=k_(+sX^nWX-pXYm-*=|7 z2QMc+sgNyJ5FKn@4SH(lVKF9#%J}Pihg9--J$7?n84Tx=!tW`)= zZTdky+ZdE1ZA9leq4z2HXGXk~!_L>Cp0z2xWeQpwy_<^GSw|Zg_0F6&20gq$QYyg& zel)H0)X1?BNZR+$V(iOOtWC1hUMQ0xSlFmA#8k%gmqXlHyu4)4 z0q$x8Q_TZ-L|LxH>|E*>wi+aZoAAg>4No9skCODPV^QwFEr(DjagR*-3Srj!BV^K; z5F_{{JULOUn9v&3f9q@>3fn^p8TOTevWgZRp0rF__RYKiVfjJLOEJ*tq)mal2Im4w zG@ad@2(+bb>XL>1Y*vgQG`~eHuGozcNjR*AAy=c8V^TI#DLaS;nFyQUDd8WTCcL3! zIxhR;>GK}614ky%xy%niqIUDI#l7kCIV5WO`&h0CTGxc??kciw2pJ7h!JQ3Lqn~Y> zV~E{yRPFJ@;j6}{$SnUA1S8CDFNmM^-Mf^-;j1R_q6$BYQjb(TqF z4rK4UH1^)(V?g~^?=dQByqjfoz7c#B|9is6;YL-4B7O~!z|xAk%h6Kjt~8Mja@IyK zTdtTiB5r9-2@{v#X0_{cA?RJ5SH|L3^WY)$#3l}A99vz;CsoS1| znMZfOGxgIfU=P+{>QKjjEnFQ_eZy?s82aA189JxBGS#rVFTk(!W?dBFjI0`6|IVvn zX?7a^mStybe-NG_-xp=8WUcMa&2*(p#ZrO zjN8}`Ap=X6@3fj>oJ8aR5cq^#M2@w`j}7JYO@@t_c+l#_ag)@~EpeH#0kZB`L@1N4 zykAuQE27SL&m`OmxEm>z--(zw>X!LCd-*%7XqtKB{j6~u3-nH3lrt#@o3NNgq2H(8 ztf31=AG-6WX@OAwb{GpHrubT0F`djkGQ}s;s^OgphAUeu~b{S%BPZ)zyA(>mE0dYXZ4bjE@V6*v4BpGTdy^evCG@rcIU zF`V7os~8NN8x{v6R>%r(!2J32K783?=y(EUd zG4Ym*EJGJoQ;VVK=&B7}i3`*rofikk^f$v-pkgOT@jMmr^4`3LS5US zpAE1CW4j9UggAy?uJIcTQ=q1dx~!CU(QY6LDVw{i(2*6GQqkqI9<@f`C+ZFwY+?V2 zvfCgsQeLE(6)>fEUcqX`&O1=%*aJ$@LO=kMVQIOaO5JBKou^rQ@816MV?5Ui60+UgUYFqLLHOP-9s z#Llyq@<9yQwiC>H4Ey1GL@d5OIfYypgM?^F9N5H%85NXl>oJhV`0 zC4&{JTupDQ&_PWY0lH@-QxgC(s#|G+U909!+3BNd0Ca3~#!HfkLPJhH?+Qw&Me49z zyqMw&@m771=!--seo=^O=hd04JDklBCuw`q z?t(foFBM*Li8i*&r&FYC=lj#iroo92EAUUGN$*d~**@4k4p4tYdAP@jAOu82A3NKR z3+4np?Y&qmj&QkExqmp^WU26(R?Nj^2h-VeeSGbcYgb?fz4FI-xo_k3$($p3L`;i^ z$jydH3DWmC*%D*G1`~ZZcAo&)7LQq+PbdL(*I5_5x}5lKqAht8r@IH9t`Z^X$K{{k zq0;-ti&0an+}RL|>eX~#X5HQ?Z50L+uXRS77kKq|zSP^J?u~vd|AVXY=jvX|AGy@r zCLb@uxr)oI#Z~sEFwl3@Ki6R$1rt}0k{ixR zY6ZxN%Smr!M1Ms+tn#yfa?J##nhS;$bTwmdm||0hj4;o0<|_C!{Bu2|`|QFzf2NMT z)3gH0gTx4c$5GevWnD~9AWcXzla`?DgiVMk>CO_pi~=Aa;YX%!;rWWH z){ttJj6ux`mp}Uy>qv<;$g~v7TVsYR{YH{wrFqWt&mnTkB;+HRg#twjEpzdsDKvS!Fhm0)NtQO zLepxroC*}HVZWba-IA0}14PVqh}KM{=%H=f0>$oR;aTY z-Kb5y2gwX8QvqU7T6Y%>ARe`*+*i`)`36u{6RnXC&y0AqrYR$&?xDEbz3{(4fP<0$F;X zzALI1HPaRnsxm|nHYZFO6?<=qC}>!s`fVg3_VG+4w8Q+a9;2%HeZ*=bsjiNcH-QsN zGe848k}r6*q!Fv?q(p|K5yS94F05$BFmwGVYC!^qZuK3oBucxi2+tV z#Cl{k<%BCR?-PLzxMfPL8&t3IJM>)U!+_BtZ4|N-2l?joiw9VPhYL|m^%yYvXVkL6 zODtxi15_u0{F(ZTYWA>mRIY~+bI6kWeX@IfqBq@KP2_ny_xqfSL2dOvJ|~09k5oY_ zCKNu0H(Qr(8Fw*GTC3L zhg6aWoqZfnqHRc0hbo*d9!RB|viQf#vZZt&Vj9&uFrrISovq4~x)m$^W-AcMbUu0o zqT^R!L_dTNVW_gz_D$H7!Z#iZ;lk%)xc}qtrQ&1fJdQkhJ=3ukl&@XmqPaVMvI=(4 za}|OziWUa12ekl+hQYnNd`gTN14^EE?SvENk;KqR#)~b4PX;_>UNOEDUPy-*CRIS` z==sGL8EHwy0=urhP}l;^Fa=#|O-d{w%U339hE2-Iq7lREPeG9wEw$5Chg)#;A8-g& zsh`(-8~u0Ld7l`)H)#NPTR4WFd7bESh%*qr$~;p1#_2?`((p8b2uEGj{Kk6dr&``> z@lL*Smkc4&wOrEdx`V`sS3;p6{Xv$aT*c~M)58%idrmdFqW9!Dsu6Mqo*?FAHrzvX zj`?`{5^@;pe9@dJ>k0gcz8X68oAl=>aWrpM%q5pj)~;~RP0D)eqzbMuD=uX%Ruftj zncOmlAg9Fo4YDe=-#DwlrW8_;VZ8>|0-=eT=&u!R*bOiyO4~cVimn;umzQnqROLXl zoQh~vY$9rjSXHb}i7W|O8O^P9q{JZlnhk_+0%qY8{cd>FlNn`Z!&)3-AuUJ+Q10m= zLvr~-n8u=C&{-W2HwfYmcN?4US~=R{uf^5a&a?!+5uK!>Bk-lht<<^?5@2v^Jf?jl zndmQ5k%GrN^-OZFH&^i`b$%Af-2__^@O?7M!93FC#)}RZdRtunSMV(t?rnqbg`o^ zr_k+yMC=6%Y}%ICuF9S&^{7getpxPzlXXaF5G5k3Dc9{Jw9O!?l~KaqF0?dy97M&a zL2)oG=aUVuA4-RfRRLAGFy73Z7Up7kIgJjJaA*N%8m$6k3K6PrkJM(7VHC~u=JG(GOnd7hwoX`u=VrYHEM%BuSV4Z8y*VkLBSyKG zMJ=VGjh7_;lTsm2Spg%*ou(({TRXI2kmVbV2j^>B?^n|QC^mowf(_yX!*xHIH2i&biMl;>|ck)@& zU*E2zN?6Ru*mCl@9JGUo*7|HCq7#W##U3ga)9wbdo@8l5aYdzd zJ60I>f;RA16|5;!>4vo_whdY7P4X_AC(KRtSSpLD6${Vm3Ek#`$#|Fb^J`7&W}F7D zT-(@ZoCb35Jgeo#rQ&sGpspTsu*wM3z1oaBY|GT{YJRQR{Dy;=HG|VfTm6PA0*JhewMjgdm2|4^)|~P`A)n(+xO& ziwaf}Iq*SGgVL{hIgXH3bXDai5Ram7NJ;wR&SDCMUu+ILAYQnB=29a6YTLEm@)Y~Z za`2Yzt1c|&&As)h0m7`1wIi zc6Fs8>vkRcs=I=d1GkgUU_wnM11f(bqweHbUXECytnb&1W^bt_wvC(QW9)3aA`g*B z`4fKoZ|1Fiob}T(+ACgadeZ;z>@6MbV~4ytFUW@^=6S4O@_SV9-AfpQX6OP{$NPe?{x`e?id}+XU%~`Cugbm*%1zdWEfelrCz8)sMimx~N6rXRiZu(^YcSc}a<@Cv1!Ts0j)insgalC8#VS=$UJ|wOs zK&stUgxSV#Z`d0w-cyb8gsU~VRRcbJ}*q<4MAWMSJpXCYgAQah8)te6~z=Y~;z+z>XSEMhM z2`-~Gx6?h$qQjFIR5K5X+{C}BeCTM1tG%@Rl}>Nqn`p#mAFj?lCeA^CJ%qH1ux7{x zOo@NUrUQ*9v9=@~Lx$1g<{G`i6l!X82!VG-8HLW+H5Arv{$Dfh562@!XWJ+->iMn* ztLw4BrbRADMUE)gBWNYx)fE_a*aUDFK<%PqngjYnKwpUX41$oS7j+fEVk$@2oeZQ# zS>D3QWbMnvwWn)k${8Ax2G~$oj*6jAY-ntm)C$tm>agHfz?s2Ktswwiz#V`fHQpRh zCD;lc)3X3~^q2v;gWcN!?z}MRx#I5s2Y~moY_}$W6VzFA<@$L+{qCd{*tPsm6Wnj% z;+wH$7~93tG`%qBujcMu;Ci|_VEHg9QPj|e%wP)096+2rK0F=|7tu%yvL%blSIf{Su2eGj20J?sc~32Q`O~M6tVd9R!Pk&T0WBMP zS#;;o{N!aWZi_7Y3}J{BCrdV|yu40CUL*!^SJPWkL|(cV$WmV@cfa|o1Frr$?*qz= zzS*9uRI8#F)hCB{GxfxQeib~sR*50ncr0W(u+AdryZykwo|Hmhd|u{{P_(*SOp<|% zd|MxDF^@^{A>xHH{WS!{N%8MU-h+I&mBiiGph(GG;o|SkjmyR7Pko903EOI#odq^} ze3jp3iv*#T>54E|D-OkZTU?75Wn$!zF2$dq*vQjMmzq^d5O<0A?QpJy<<Kz ze)bF@=ZHfy&yWV6?6yKjSfqdy~P zsJW=$)NL?3-p9`lC|rqzRoQAPeHHm0#X7$fYAItNk~O#4x*~;6<*r%n`GIf|U-~Hn zxE|VL|FpkKP?uKXg!e3Haq14rTBvd7uQfd zz?GjijSMpkBgDWO6g?@3fwO+Vz3f1P8&q4zStYbEJt$w0y@l!PigTg(QF(|wA7$WX zvBiz#t5xWE3-;KWK6Wn2^n&au$BfR)=z8#iC1q+UG{o*g3OGP@Fa!->NWt2gIrh`K z+YcmMrW^nn-oB={uC?4|(`1@)nuw6iQ*IFP(p4g;Iu#?@%WFlyp-I(EI@Oucppy|K zJ!Gew$=<@b8Qy;{QJYFnEqq`Z;;m}P1rbmy?(xw9{2Y+ItCrf})M|afj|5NmxM-uM z)5SeT;cTJ6ihAWXMs!-2SXV6K_f{ywC+AGXGbV@~yCBL?r3(%7sco+8bP_|VnOORc zCDODJ8D*KtN;J?_-J~SluAa{w2K|$COu#cu z!96$7u6;v$)hR$CLBWfwK+)RW?JZOB-Wt>`N)j|kMs+@F1h!*dfp{1Is@U*-TVIU7 z54p!X_W8B)^A572ZGU$W!8!;{>K(g?{wEQx1{M6ZIFS@%Do&n_@FV3hMW~E_F+Qc1 z5i1m>;FkFZ$^i0_w z5r5dq!+Oc6Ot0=-`l*p zb-CF5xEhS7#-q)Mvx|-KR^5%FO&xx9IGx{RL`EaK{&FEJ%}6)R&${}Xogu{byLJ(V zRzzk?!v4~j=+ylOr*^-X-j`F?`8bx)B<&N(CQ1N>23^%l@dEerj z^*=x_CN!zZ3tO3;?2VKJo`83{qHGNJbuNEwMjBf%w_cBFNAZ zvwF~WF;k|2JMHRoc+(IB!Ck)WUsk*gp7&ckV#6M?ZCFDk@Wnl-t#<0v4F1*6&d}ys zqfO<0sW{Ly5GJ>NqpSVaW~Z#_W43DU#A!3!#1?L%<>n`i#pMImNxL6_6L*0)ob}`& zBkc-?(1fRVMiaQwP^$z4BgPS*Cc&kW;C~PYlgOrkvXyGA)JRg zd-PN%kMU|oNbefVwJdoV`Ghl+aXt*41h5}W4_&lyGP<@D#NhAg1mQKg2Y~bxdZxt6 zFjPjx7awD=rDU38JqLB0*b4!&Xst_SzzoUhv+)#hJ(K4`@%55NI7)Gs4n#LFzJah0 z1RwEcRh88c_!-?vYur3GL@5^SXY*)^a*aN(Y&b}O^F=un;)8%a-o)^{oCUp#E|W_1 zzlJ{zAMejbM+=0ujxiB+ncm&r-roH5;~NBz$-!`@_r4;a0d*d+km#s3BU8sx$RKu6 zs<9nU%2!}c@C{mk$N88+*X3vT<)mVEb!MP4r4x2#{dF<1M$vcVKyF@DUZ4U>N0T7v zJH9JVi^sx|QRQ4@O-65ZoMN0&R&+q&u4)IVfPL1eTTay$J&37!zKDvb2}VK?*%A>X z#L(DFVK2bAUP~|IIil(U+}7yI3f4P?aE{ZlN2_-%R3Ah<$keJmqoJ<9f6Z53r`EQg zxyT1MjbUa+uqmpvSHNz&2hsnUCT zvr~ZQylt)u?szjMS{c5GWrOO=yMB-q^G%v>n^H4oB^y-Ha@U>@;D~tDm65mWKjzILJzese@&jwT29B&>>RUQPq;tkI2v`M5PrFpj2 zG(tYX*A3R5dWf0Gp!rNOG_1qynX z4~MgPd58Gk+qhb8@{YHjHu$L6*tp~s!ZtA>{8v*7Gsw@RA)A{ltJVN}pg?ow!wa%1 zZFZQIrg9%93`?3GAn_PG`@_R>%yMa^-tjc&B~O$7%Mr>smj|PvT<^rcuH5FExA9_2 zg4$P*A{L{4r>MnO-4>=U>*-^;Pc!vkY+C1v6fXU8a|3tyJ%L=Ne^R%FL%enaqHa9$ zN4@c*+z=ECMrBwTb0sD#`^44vHsEC_z8=n+K}Z|Vrc?gli||hXq*k-g=X)R%Bnz|O$5>J0Pv6wUd8 zTTt)OrX<^v@Xp{~gJX$2nwgE%u;I~Yfy|`;E_-awtaJG^dLW^Ix@Q%0sKYJA@n^`h zTHwNUI87jHq8zE%GG-!r0~VB25SoR_v&F1D#6`ckNQ?KBzVN*`{5Y(43d^xWF|SNq zYzJrG(>1}_n*p95ZGY1OMt6{M5ujX`k+P%IS!EDn=Pze*hvx-*+GD{qE5CWE3OEiq z86`}&G<;L;9nX-KH_%~ViebTlq`A@gbU%v$WG7Q4OgC!_u8 zLAkp(o}#?+A8$LH?JiLBv==oZhAj;hnPwLGZeEaV}nQg zh0G15H1sif6~GwkYNnX&po$wROG7SX}^mjN$!r|=4`Drr&)@#$;fB#SM({T$b9F+eW@)xHOb!@Oc8knFD zKrQPC5E78#ioFP_)Mh>_aXrF5t9}Y7uwV=E;GRIlC1gYS&pgU0PY$l&n0YHE-AeEN@<5^KyQ?fDpMRxpgwma<|`Ty4P&lWfN^_+h)JbN3P>d zbfJ3=V}Sr4f{^VnGOnVpEW;&(T)lPGZ(8r^Q}P&Fx1_^F)u7602U`007%qLy6>9IR zfKyBRN>4N_^0s&n7t_0HqU(7-P#9pT(Khv2VL!4Fo3q&jC6OIUb(N@xM*@bAQT!F= zUh25Ey7_nnTH?Q&;Tg-(&TO1^qLB+6H_s&WpIMDiD> zg?=xF2M2=D!*LokHA1!{Om*KFNYOj_jocc=VJ0b*+8uUu9QMERz5^!JzUE*`LAQ- zpz?BSh-mOgT2&so3pi%A^W6|Tg^B`SpG?Zh97X%k&uD*~DUFBv#-6;utwLUEIlnT5 zr1AWCdOY8RV-+$E=A2y!+!NIU;4&`{N1L;9j6?xgqK_xVGsyQp{Na-9+VU%d|3N<| z^oSq1HR1u4%{iGK7jqoU7)u+!9A?*)?Z}Gj3pSw%>hH_x%-~V^eEZeW zAdomC4nO?ie=CLkH~skG2mS2p$A|jy5k7qTfK6ZO)1H1@(vKbec&Z;i>&I(;D7E>e zO0ffMqTjFHp^-=TI_7kWQf$ZTCzw{ytp;clJ&4{0{747G`HMvV^=}~xmzpBd#t%PO ziywY?`oj-$Svn1A+UkcNq}>lcTDb zx)z!m;}CX!Ecb?cE14Ws-Pxs`=8xiN8;<3V-TC4KZ0$YMRo65`rfpbDUzKKJaa(SP zq=hlyEjFJQwPW|Sy_qXpsI(d=PicOt6|yn~qv|w6#uOmzp4AL#q`hfm+=oX62m%*mM(hf@e0)~Mza}K6Wvm5>(o7*~ za}!4KP1wG>Y}ynK+Q2F6V;MBA(EL~5#e@S!i==lp6;ZVy5m3LT&2r3t}nHhZ^dgYc{5Hbr9 zI+SwhnefQ!a&eI)ZX44_b!!;9x>rt~OGR>PY(daMsz}@yuQB6geg3`&6q z`+MGzczl=(hD?cr(JM_vkgv=_2v``zH6@yVur*+!!N6W*{M1#XJHSsRqOZA&1`_8l zkB8CI3s_GN;AJ`-ju{pfMX|+^R_XAQ=r9E6=q0)G@`^8r3VS|Du?X?@&i3Pvi_xKl z^hoX0WRxxEANQXl!{T_aKbl_oyJDSG{CbxZbDbQxuI zim#%M+vDZ789n$@BNa_42}&iWa`UPsrpaHlGcnC$hWoov-OdhXuW>!cX1Xq8heZVr zp5me%MlH$7Ql}vZp&#gih@*q+Pj9WCtG{!w+efYPv{#vh-DmeGkD^oyFMyA8%TrL6 zY3hC?y^XEUnpX7B{CxZqag&%+Z)f8ZkUuuTzgM?-F$QH8JzW=iLxb7*1nFv*3+$nH z(^O-$X^0%M&$zLdyO#Nvs7uH*Y7%-D@R?7J$K&iJ=n%v{s0c|3u^?==mmgbS|44oc z{ULM?6Esv`cxbC^M$jd%)RWohP$(^ShZS9PKA7^B?@g;h@Tfd0hqz>e#wAU1GMF78 zZ*?&`Y;(h}fj1W(=8FYmzCll#c7TcJ@F=_rndCBvK-&2KXYXtLn>voQ|CIwxD;aFr zkfgUIA&CQ~bxSa>ZIa&CaBbO^je;z>k_>SP|NHwq^R;`vgiT1>``*hh@i{vCH9I>q zJ3Bi&D}B{oR_pooxJTP7n+p`2>lqBROt*6jT+lET-@0|HNwxP*~3fda-+mg;qZGSmG!~7tao4)J{M!J^A6JXv693 zhVdK^fNu+#)%cB3j2CU^q8R=47|VKo^b${ru#YH65V$-Co_WIPA#LD@1?Z@ngsw}h zqIr_UBux-;_-`CJ_YQVsCi;z4c#x*Yv*R)6MNMC|^k24T_R&}3Z2=5*6EeRYk%&}h zJVmOpHIZ0l=Hjh~o{I`HbW0^NOcV<~2w5FU4K2q91Yjy%N~T${_Pu3mrrY`Run+?^ zB(*=WX9A~*`eewwmgZyKz-EL#yDUQtR&Ws0%S%sjNy&IVbH@NNX(`mg5K0$aX17~F zts$UAE@o$nA9ne&_%u8sU~sd}d&i^>-i;wIcV8@Il_vGpyNF{R<37BvxZ|4$x%oWG z4s*(O@Gqn3k3LgfbN4Ov_*z6I#jdaqyx+3(mX%+$^LB;e*!;vzA_|DtT`G|MQ9w?d1nS%q{|HT~=!Sg}2A0V!0Y@$_I zOX@Ep>yIv~1*YhG=wB5{9ca?Ek8YY{v0+morM6Ura~$=$e5J8B8lDa3>c(yMGL-Y3 zEXb$X#fYlwB&#B%c0+7AlX|nksYt}ERJ+g?C}De9Ib0E^>J{i+b^XcWKp(aTVbgjP zf@Sw2m`q{lWFIp{hRX%{Mn5$>pR2!lkXTXEbdI>S>a1==fryd7MhII5&xK{6z6$Xy z_RL+MF%NvV{3)r2E$b^Vr@1>=#FaC5Q#K%&%Q_l~- zQy7{IBiEbUS>(7lqr6oJIAi$e*x~NYh$J>jZzb;)`8tF!>jl{Hv=$nc%$} zzsdxkxz=Q74X<*dw0;swkd^F@W)T7S|Fh3RnIY0oj>zn7hpBMuVK$G(?0c2tPdTy= z6vw~l0F>5OIs%2*#x4jwGDv<9smdnh^HbM21l7>=Aryr>3tO))O(o4GkR52Y4QDG zZxYKegAHO3Ucsz|O^Bnx@n8&xSlqsYa8|fx%MiVzmCO#%9BwskI17`ONt+7BF+9*l zlXEKN2!=SsQJt*5gW_U7WUzoVD0?&9J9jjAw*5Fet@Gwhk4JPqpW?{&Og!xe9+BHt9Pq*O}nrHsGSN&6S-! z(EKZ!zhQmY2GoO>5Z7?{<5~3?0p&TY!^uw=(Gp;q4}e9^R;U86y(6hyG4Blk(b@vA zumO5#fVHN@{pu&9d^FsA6=V60?Za)^ee-*ha}MY1{#)Dzvt)MO$5T(R2 z_LS4_*SW(|UPKjAznoZWk`F<5mGySsl*x$3#w@MU99pu3T(H#Js^X)Eomlvw&YGIC zq^zZNggV#THo1i=PQt4Oams?%MD=a4=3 zJI0YtPdg%&W_#lo$qZ1a{ln#zZ`#+Urz+Nv4 zvAw*K)wb2W8aZw}FamTuxU&Q_DHTBM_0wo{ch?P+Ac-Ea(PG@&iYLs+{ z%j#?@Hhu>U>#DpzUmkw-fu*y9U}h^*rP9J5*+fY#$KVq-;L&9XqMld z&cBc!T7U^7F$D!(TIv9&jf~Zti8nrKfi%w(C<<*5<4h-}$_feMLu+Xsg zqoH8KhW5)<`OUFIVjEhdI-q4wM;aS7FrRaS=0($>vk4Bl){P&US$;000uf+i9M?WL zN9-a*g?9KMAVKj>(mCl<3n}2YP(V;4j(#d}L%`n_>XvT5m%gpHO`X;HG{a&V-`Gjw z9ae4(?a8Akn!$f`&qO&-+Dc%MHRiJ+a* zLjb_>3To_eGyiAOWFbKx*z^w{Gf|z`H=FVge*8ZdgXtwg>S9Ob$G@lT6QN^v6H=@L zrvCBoJzkUj!7QB?{O#CcbGVEb*QTf@16Ie6AODW0g2_uLGwJSv*5`oPuP+-8Lea>P zsos9L;ndd*kxSMqrA1xH<#s$YO?`rws1_aVtV%ShRfLEiaDCYOaW*fLNuY;nNQO4B z?)|R{#IeRY99*iEQU`i|Gp`H;ssSLFX-BmvEHn=pm|`2Dh`HF~S)B1;h{ZoCdQ*X5{ONqM=}7+rfO>u)Wja&METn2yN#^wKg;4psi9f?|cmW=~{uU zab4@mgk8dDQexbS(93juz`FYOZFlea^V##~J1=g3z4Y$g>S=2Iy=4B@CH(tE{MiMF z0vRU?)93t8-zlZzCv1`SII-TuQ_ zz;Q8{PQ`h1#@!Kmb#i9`vkK-CdLSjFp3Hi05Ec$c5=Vob%kfc{m$LPKL}c+UV4{hr zcl74C3zxwT7#qw@??ImU*V9kD^PHId%g!za;BD!90Y+w6#pgFc&7hJreqDavg_K<~ zQYHJeOL)8 z?bhQ8rb;`OmWH+#Z2xLS$kTd?FICf@0omitvDn|=;;Q>--TQ?DF5s%k*~7s}pBwk< zRw6edlhSNXMzd{ox&eY4>0+{+r7taQl-!@Jg}>rLGqfW2n%SqNrhMOvArm>dwW~k6 zmLE1z)gV|`ts}DyhIawIlxv;Q6b5^4ErBss(ac&odop7n&9GXMi}Xt#JVE$B_#Bps z+JsBRkaGfs|MQy}5rKFgs0@<1ZVC_XpLi#Yx-S+~!;+kKi6XQ*9Xt#(IH0nv(#>@%@Z&Vw+rVP_Y2&?&w9-SUoUYdYAN?Yh4hd_W%)1+VQ5xYe`6{V%Hl|JhL~MqZmq84hf3V@OpOcdluzN|0RV(4Z%N(1Qf=i%yx_a6t*t1nh82)YT}GQq~bf z@Bhro49&)56)RE}e_RK|t3Z(tV;v4ng)Dq8B+wY3Y7mILMgfCK zB@x#GOO;?M;G_}sj(5AJB}>EA;);S6rFkJ@fdgNbr5El_! zP}se}9eWaH0CHgcc!G^SsByS_1)gw>4+wQf>NoWMC+EIwoERdpN+xACSYBnyV_X?Tr9MK zf*75OBQN^FBORdDt^=8$X$T4Q2!U+4E$b>cHE%2gLX*Nm)0#`{m(e(=9QPQGE+yvZ z2?Q!HH&7k^d(rbb=@M6%$MX3XJo;3x3KP1GwY$TLC7*R1+$(P5zGynIBbG2{dCjP- z**E~M;4T)fvKSA=y#gB?P?f+@6a~?!>uO0JC=Oj~h6W<|h^|n0fjDV1KrnIoO_x1P z=h(b|V*?R|LOvNjwV)*>^VMsUtSkmgKx zsKuMrA^t!*%&rJoM2F9KO&{B9pupaH8NXfx272Zn_Uv6#mUT{By=gZA`#i} z7y4jx$hMYK*ct!<7xBT-pUNZvfMmt1L_uKXHNuDQ!eqj%6yq-(lp5s|F73VrAgUYI zH5vL@$YcEyP0BLga`8A$gi8=ASafLH1ihBcRusDc3!o?bCZmF^!>lnZ18#J!5wXth z`V~X+5%;piCK>d(Qe$;3hpH&*-MPe7DkB<(wUO!>8^fe%i12xA%dP;F&9U%c=8l^r z?eNDY%>YEd)xsh0_p&K^0Lft`5hiP4IV?JP4&LFkULWO0hoU*COH(XoQ2UZ@2_=*_ zPOL7_{xw4EqpNIWoQ&)LM+q@TTU#K97uM-ygR}fPg**l<$Ga_3bdX6Om zF!*MOp7y){sT~A;&ye^z8ka|L9L6zyzXLp$BW?q`*eAu^l{o$;&Y;*HLUtI08-jkT zyFocQ z<hjmcZCl>L`jflwwgURG;dBBQr0t>h7uUs{P)1QM zT3@r{0xt7(Tg?9LG%lVprXYcXUfZLSw{!!VGl3SQs%poJFG-z>`D4NniSaZCpzNPTCOGqbt{W2hJ@Fm zSzTFIJN}-#)Bvnf01vOy^RiNZk7}`0R#Eqpu0M(YGGX%jYR z(krOz;t+`EHsyUAiVRoG#0GB!!g{A8Y%rB$s4`b%KsDx87@ur=lN*UU(iG6~Xw*l1 zI-Z;_0gYW?bt!922=1>=E3q6hmN}NWrkxVQd1di&O2N&GqNb@ zaXfglA**vK506dQ`eLY;$B0&U{~*i-aLI)e-TRi-QCA!Z`Q>D*$Mk8UtB3-f^&5mIZP|6Nf_NE?R5+ zR&nqp|M-G5syivucfI`}A8;C_RZ<`uW! z*LuJIkcistA(_0xfxRqtwK722GUEBKrPX_(+GVGuD@=ocL!;;M(59BX77;pd-X23`7Uw9VoV)h z|I!urH61-tH?Bu&?s|}Iu{W$0t8upiL;F2xST?EK-8`;VeDMx@wGJa@&Kdy%2=?R0 z_QcARo^x~pv^yT31=5@cGbgTmMhIG@q3L8e%?(I0MJQMC%2Msbe}6hOvc2ARw+x`& zW=A2`M1lP5Wam%VB=Vw6=5Wo{%QYc}v_UK`2fT;{Zo>*lGIK}O*U+ZhB+)a(PD}Nf ze}j8azZ36!iBRNT%$)Ab3p?XjD+hb#Ex2|uy1NRV)JYU8;Zt^3vKkb-u&<+n?aTqo zkdg4L$C?eP3Gz0X0n6_C>j~~=6bEJ*J^DE7L25vR3x%L`4Mq|tAiSk-$@&~$B@Q%H zll@-J_1p_3W}#i&NZLcR_5RM77CTn|I-KXDn6m>c(U1~f?dP#(qF-Dj@Aup>+X2dK zE^O031J2+W8o0fdY~Hk9ASc)O+k;u=OV1(J(EO=OaKXFGZ9>*Pb&%HrA!Dqp_X`m+ zuvr7UNH=%f4Gcw}C_@HnsVLO{d=SFb`_Q7JeG6-Vugzss4>Pz@2Fa8hX}>U=4@M_A zVuuwz&$^Qim^}E20fn=OhPuuVx^xV-T(ogK8Av<`oH~^1p5Ig}CJudop&2StbcsVb zpyV8sh%9Qa@$vOT+%@v?mhJBu7IqUtfSyAjPfQVdh*~t$nst0LLw2r?5L5IOl6*k2LnKVcjjRaihvNviF#5FHk=#&;c~*p`AQ-k# zb5JNt1fvy*Sz!BM{)FUUugUoYa~Tn%wEY)Z6&g~eYka)a!`T(fwJe?MNs+98?pHmY zoX&~>5F%&R(OJV_4pe6Xz<>d|P7v3$EC3Yi%lT+#l0Z~riKV5(Dx;m9;l(NWEO)_E z^Jry0!SS0e(;PKG7-f$h?*E>C`#cW^`Mb;_uz>(w_GJ$r;J>QLOR0vmb?5R{vse=? z(&9k`fAx{afFi1rU3LZmB9ThZ`&jHD3K6(NXDqe$m27b_x=|CB3=}B3P(<`o->K%E zQgXBj+r9Ibm$1AcSER3a`KVA@7nQ(f{p5ylK=Q*S6TlDU7XeK3tF^C7Xg~jm7^RTu zR5*eZqM@41Ipev}>DEcHpXI^1=0VZsk_0H0ZT%4d5)XdPXQq3W%;e`FxZ1Z#dMpg@|a@q^~Sc(V8rONOPLS$4}6U-C-;^;8w!Zmk8tT zzq;(A!QeF(erNdC(6msg$i(k(_n@?x2}AzQpwqoAyLN(Udv{)NA0V65i}RYQ7CqwT{Koe7*7pAH#@}{h1d!clAiSEm*-PCL;COWt7njoX3m-fkM{n4Q z)-^*a^d$g^ZHOTWMzWIbREr(4+qX3}Zagmcj>QQI5YESJPjV-yhyiN8s%8q%YnTTp z|4hj&LBs3@dsc$?Ol2ja%gmkOD_(=7@kKF`8;n{f4_PGY6cJ+GwLb(3R}+VvwLB0} zZpgj`*m%%6-{1+IQBE1DLTf&5K0|6ZDgF;Ip$xEpbP^TfXl|NWW{we^cd&Ig!YM)BX`fw#_0TYIziY@b`-$;9?LoD31q8>g`S{9XrsYrHE*SqXUSoJ;J&d z2WoK{T8R8;_t%<*woLQ26SwS?qLAYec#Z)R?bO6Lx)*R>X=BkI(ADhA#e>INPd4@+ zZfrc=fAo0$Poe%@i#@d|xRMG>H4y$a2=HzXijemO8jK3Zp@Ok>M8cTiUyKXZA}nfr#MG-w&F`uhm?s~!dG(5)TS51 z7*SCk9uL53XN{f{PV$+{uBBZ@LH8d7SR`~fF>i5xe(kPAqLuY;kbO;`=FVkObfutP|_L3AYr z($HYlV*-CYoLr=}WDMCg&t>yLaG;vOyQ}8EHDY7m9a8 z9BEtb;wlc1p8DKI^A1ii`#bI~A9Ok0N2$=A$FLcXT>xh0d^@qaAeMXrHnj}s(dmc!pq#P_ZquJ^SR`xKJg{TP1$kjs_ z!EpZ*oFgx71;QYBh@K`3v)Y`yNUMu_1mGmPT$}#jY0u5O2NVmsh?SYf2U1qx9N$)} zszj{Q(hx#%LD;3-tU~iclue>1Bb-27tVpFV5*D;?D}UP*kQ=xRP&O5=DpNzLv=$ZC zR`A}cnGF~sHZV62Pv}E=CvAq}gh*vT)NUmM2rtLB2m176j=MMXu+j{lKBhI#ljOwtmc3h7HA9 z@lanf)_U;Nwpl;8CwtlvU{cWgVlmV<1Tg@`yG1ZMSHBN9#%`(OSOIH*C!-;S*~!J9 zME3(x_5BhEAGjihIn7MjxQb54D4X;-Fv`e`+T~A45YsrN@};T{H0$cCOu$eIIy`kA8zDEnWQZk?dUXH4tMP=ODGZ zVsSWNw9qsB9?r0yIvmX34B%2^6N~rO?V@rhL8W}j*(vPIGMlM-Y{~#!!kVTECwtXG zFj0JT)AMll9XIZ5%65Bm^ymt9=ck6GgdYY(_l_M z#rz33;XWO`)Q{9BXGH~l$Y?C4upeP7cn9k^2xEA{VC6JA2>3ZU_pziwU0COG5e(Vv zCXQ@K6Awqx+AP~Np*Aj07B5A%u4GR)L}1PpG+upy;8 zKeJq)TdvjC^3jx-DXqYC1s6l4>dJNZ_}R}nvJQXDuBHHMTYe6Y$y9yvZG%^ zzCbGsa#S4*tMCK3b%I|(&aT%QGl5nPX49kZ#n72MS(fBZRA{BNUg*I|Q@y&F`31Zm za3q*b%6$;`r|OavFy;T(=l;7_-^>u7j)6ddB*Y#{Dz#>-2G! z!a9Wizl(}+Wy%GGE3IAZ_AM8m)rCa6jBtu+5fM={hXxioW2~gA5&>P=Z<-ZrBgfW2RN`p6&Z)3Zd;jrKImG%5imw@jjYY2HKAoYD zw)g1bmA0z2Wp#=wxrJTD_|vee=jk>3^E<=|`MUuG0(eWms~htSQ0%PW4smObhK8LFFZI&feV@WS%4J+H06ur7|4& zS4=i@=UN+g?in-QWo2-aX5DL@7x>}yd*zyI%(`^~+XlI-+2i>=3`5|> zyft})Tl)}N3*LxwnXLxPfDbg*el9%RdC6SM`WDAO1}D)lnd=zlli^tRQ#D2H$oejh z1!+@EEXZSW1?ZNg}bnrx^OHK9IV$!@TS%`xEebcC7?*|WY6ezw%k+8xt;G-Yo5zK!OPO;TK0W zj7Fe54uE=bk9Btc?K^GT0u&kF*9#s_aMqzeh8f*M86nWbaD1P(=oiHf>=nRoxV4-O ze}a(%!T~!Q%tlJh>hx`f*xC-XY}=u(m@X0m+RW+R>Ebmmdl;p|g>He%?2fT4_hXb^ zw);9UuF5}~jaT>j1Go;nSRJa7@pWbvgncpl73xVq40%K}aKW#jL0sxfso;Lk09V^` zR;8Zb*y{{Z-0f7ko^S0ed1<`JDT%9=UjUpqWXZSzV%ssus@<pXCFS=Q49y*Dk!=(ZHPzmA_&6ossOrZ_qVBhS_QWQ7n zHl1a%?^*LUPt`k{V=BfhbZ3|$5D9}Ei3+k#2KLd*j*dLmA8An7%Nv%dC+Ve87|sX? zs??WUea+A=s=|V!L8*I*8G$G9_t5GUWqT=OtOSrxv6d$SAToG{L5U_Lz?Pcu!s+g# zhH9i&m0}8=AY>gxq$Aeb-f|GpoIul%mB0@!a1o|r2isg=WrIPC6)+){xPj)Ypg1|Kq`umh! z*b^L@l!U&B9_R&CNduMILYc*{XeL`k1z_5Q0fw9^LGm@$_JDiJ>N9k(e?VH6OT?3s zq@HPN9+XW4pBwu?)d`&7c(f{0aj37=bfB18V|w`LdW?e=Q+9d#yB(y(HUm|EKm_}} z@dTQmC~o4+B}2jE_k1DEk+O?CQ)~zdV@)TMc@IPmfzEL*v6ZJ4lhN_R{_JJYQVg%r z4@)i@&t0UuS;{f;v0P~H_TUPZ2C!wPrA-Se`Du?Qlk*V%F)3$0sqy;48>}OGa-KUt zLlh+qMjZ+KGZUz^5BM5Hp5pIf{mxJVV)GcywF>up%9Hs4+$RwpYdBq-8KnCyzMCne^U9SUMdda6Q;;(s)Pg!o3eq}`&KOb~7Vf}&MG)vITQ2dR%wO_~ zLRj3hnqtDb7CD9sZz^O)AzL(&NhUQhOJ?-xQnF>{g7MDTHX#Zrw+?kvW{>gONPR7?IO9J0OmHd1? zqIB-3fK(TNt84-XPhCUiUF*1}terp9!@>KsU?%L#NhkPqQHXH86XJaFDoPiki+5fT z(P7bUD}pt|Vz<#PSod?RC2qFR>c!YaAGF81j~Lw3`M2)%FMbbEVZPl;O9QuXeaRN9 z8BXS*iBz@6sH(CjqhkPR|5t>Y(KHRz|I|C9k!U1|PN>urJ?$Y}CAHAvC1Pz`)uFlK z#;OrYP;-e1TK82wyFahz#ISaSrDtUaLP{$V3o)cMB25Mc z)333C>En6jjm8)g+Z0`}g?a6|+ekkFm+T}){w`gN1Kt{VK$>N6+?j2>93he{@u$JO zUGYS~QlD$0RmebJ`Y+Lde~M)hw&G6Zq+Ou%0G=dM z>=a&{Lxn_4sEauaM6@IvjV>7d2uGe_6rj&RF`L8B87lX|${jH*$i^VF@qV;Zs};5c zdYcYUc(#=5xe4mWks7I!H_@T_!MT|$*bc1^Y(GjRij)YA5&({#j0&|Z5&Z|4e2fT# z8a87sowo|8(q`#j`mg&tN7EtBE}l$AILfHDl+BHejg|lS{4;bF80=568w?nMH=KM1 zE}|kFeuPP7e7bTzK|EWXUa>>_a)=;&N9Z1~eS86dp~J|gb0Soj@+mZlQlkpq4_@E?bl zS<@lpL_a7SMx{|gV04}p(*wH0@iu$H8CCMiQNtLl)`)hNyW6moHF=1YZp@ESpBGzc zF1G?fx`H+G%7UWE@_F!kX*$-mb$g=#>@NOqD9x`tDUbg@Us!$x>vUWLQPT!c@`|vd zg8E_pJ#>oyEoi&mW@OG5XFA-zFq4tJ-qB>KpmsL-d~$w)Kzs-kB!tOeuQ8r-Ba>(=3FVEHu8oP05|^&&VuH8t;EUC8dN^k>E9`vYKO2H# z$tXDhO~b3eHjM9E_ldYNr(hwW$003jzc=g8>zF4HT)4);xye_j(-wP*uYJDuyYj2?IUr?N?1{BRolAnCJf^JkgHSsk2;@pqxvQ&&(A>m4! zbU3^nd;eeHB1QT)EL~yjKJprREKsVhE`6i#f7+`}yVm)b+G_fd*`eX~>)otH&~R%~ zbRJe=JI!CVU@y{50`pZlrWA9_%QmD(ULW|A(YB2xZzsz2aDw` z6j=K&s;RQNRyD?6q8;?#7=swzEpY zJQsRP=AXuCNWD((OC9Um+w1??bV+Z7Kc>U~>%n($PzKCwHZMX!XLySKKnKhNA4fNh z{R+UpQg1w~h%oB-qAHpZcjXw0MO%(`Ldeo6#hWuzoZ#FY1pbsBPeEBL;J_p$BF4>` z+NLEVQIm819iC_EsCOXiYdL$6#p&U8fC`5zukWI)C&Qn_k}N?q90(T$kj!Y@iRZb-OUA$QUY1?^IuO`>GQ}0tR+6^k2d-E9A zUN8*R(R{y7myvX5?Xz$$i^_4EoZuUE_y~ov-MO>&d6cLM_b8@)&4^3{?=b`#q}1^P z+~ESD6p~1%Jm5%YsIHg3T?~)w^5`SoS+&w~X%!EU&EHIFmgvAvjey!k*{3a0j_HGy z>Z{n~aqpFz(2%tfn)0mCcc&mLgnx(a^l1B zwCo7jB3X!ryNJM5x0&Awhg~BWQUh{>9Mm<3_}Fr%SqbGs#j&fHfD5|xD5EAL7{keKsyRgGTtTxSs`0v2&{ongTon`PD)-HrmLHWKkeOVp28N6 zyA3lZGJB;btXy|=ao#@Mls5{rZve#yN*%8N?^zuSM?6D{0+JPM7dwd2IO@VMzV`c? z%=p}q=uhgA%#KTm*PvDAPO*BL3kgk;gSF5agSC}BX|2$mwI)Jip`f&F;uDe)-$W|b ziR9ssN2))X2>7fe^1(tUxYoP6K=3TZs^>{ELAJx{!~Fn3y_#jhF^>>~ zgZ^!$0s+iMq(TB$k_*-9g`}m0Hj< z_^i=-e3@JxvU4%ar|7@Zv5f2Mt&K8ARt4|Os6%-nK$Gxo;V91CO%#&FzpbGn%ik_3 zfV}P=<^OW=hvnk;nOCvd4gcVy>rafb6sl*9vpSx&s++Q$bgeEn^gGY4N(MipYBgbz ztln=MKh5FfaB-&DVZpGNyu4~2&OY;{RNx*~EQo`MqxcO9Z1T6yH^eab9(Ws|*7mmP z^mvZ*KnK2@$KeTaMj58)0&Z86fV6!$s#sK7YJNtS99O89vaph+2s~t-# zH^!wjH9gH*LCro?{vyljwj9B`OTjnqBED_Xp-mk z_G*G%DtWJ5|3C(A6aT6+e+WZ=cQKj|&vCKo$J%xIAd~BvLNUauj=EUg=;|5FsU=3) zL(aKolJd1~!W1b_<@n-4)mx98T+Ik;EnGI6Vef|d%!r4q<3++2MrE*JSH^)KOmVxt zVGSo@j_Y<6PX$hIm9qWDt9HDp#8BNy1r?-gr4j!nK~EhZU2^)Io=pxv{7sXgWz0_fVL_A8pXKb&}* zwe??Oj=>mys5Rzpu!+mN576E#?Kf%fshz6Uu7yQtd<0APPGZeAg}t;})xfI1f}7Q9 zu@0vnjY~>jb3`lAnXIsYo$1`BgDoRrMQcD!aFgUK&5`dyJo*#l&o4nRCz()&*^(BM6Rx`lw@LQte2udd2 zD#?1yA5!I|l6Wx{$~xk+At_EmGF^U@GaU~O(Ix^0+{gKNeXV9V>0>p;?%7r39%Iu6 z)4wvnN|uQ~Yc&aXpg=fTMja#Uld%OnE2TnhWP1E)%Oq$_*{ZlqDaH)t50zRGR)&q@ zQBQEhGPMb>{`m*-g4bFkpM0p-m*;E9a>9%25D^)Va#?&)p`$OAL>xPZ=QIoITVt|~ zoMovGTqK-}n8|zgAIhBk+{#^kIyWNB_r5>j*ivs&L!yEd$h58PyU!8jk)5_X@u zr8W#41Cl=N59NN>c(2rA=W56kuD4d0B0h`s&VH3^I>mDGTu9d5%E=6BH|%rV?X8-O zk;meU#u~|!ezs?n)(|=*N>*7UPctT|eyY~aLk$7|Uz!rFQ6|@$dp&tIP$E^Q4ZK(C z0I&$3KpEwx+j53igG*^ap0y+n6H+Q8#4j>9`cf`+COm_`wadX4-WrpA7P34I@=Q`pLd1KeuHg|CrgJ>%34$LcRnZzplTgy=wNl!?3YB=4DxDxQ z3gsIgmD2d4DkRftDx`f>=rltOK>ch~ZUyReE(s(neJMjB0bP(L&xRz&zoa){9~#^A zl;!!Xlpp*E(Jg6wsV1I*EF_UH)kNGHE0+Y+N`aJc84uIstz2%_KRX`{c2r`dAC*jq zVs)RftZJVPkw~f|arW}!_j*~$;)-A7 zYta6fmgj5CLS1NHow5*ld@`TQ$oOjo4u&RY)cxs2C1K)gu(`fflU+;VQ9|(grhK1UK*z?RpUuZUc{5Qx{bR&ZjY+6tR@>|YO)G*Qwh8)QI{oFI+>mdCh1pYu!wF{p3lvqnrr_DOjzLL0_tgVwaK%%mlSNsbtY3b2J|8k!WIi(( z{k4*Tl6z2*+lbcJKPM9PrBXr?w+E*iKXC{&i~g)+gmT8|h)P;T_Ty{@*^iHM8GhMh z5E4t3_j(qrN-YE4>dB8`TD5e(HfPA2VXl^@n3S5cUzHkpz>4khSxK5qd7Bs$^{p}4 zl_<;8pkX6L1e!c+b!?8a8tg|c(-scY2^e^3O3bQ2js_U8mw^iKw_N&EzScgHd`{;T za(szph=l%b%=&n!AZfG- z{%Xw@)40{j%uUnzaAp@!2$c3-tu+I&8M=q6a1CdCsg~XtY4lp6!QN|GFxx1eHuzRc z{`-X*5N8{FYfLsVh$fh&F07F-oeCe@TeX%)G*8Ni+eI9;3}!JEOg*w6)l8c(N}k$q z+Iuz2igZ>&Vf|CQRT`1*rqiY7I{$B#)&s zI!`TwEF*`rC)G(CpJ1!dl6a|=lOWrc%y`??3>n2X6RLg<9!Ni{H9bv>ENL(MUCkQv z+;G-3#~}<$|74JlY4*EX*NzBK6sd|(e9{||$pQLWD|>l%I8o$j;FoHK-AmlL=xf>G zEd8uzeCB5(rR(vln(c={|CQ63y*Fj?J~2zJUq2#xH(KGNT=v!AuzzR@V!W5LjC2m? zqn;phwTNz}+pkJC+_XEjCa^=I?+sZV4X2_kNFMo7$;9bxRE0t00Jfycd2w_Unen&w zSyo|4sIJ0zdWJ>tsFaZdB9>GuC1`~UT%`7f6KY?VMFv-eW@kxFor(rL$bV9Gr))m$srl^wVVM)p5qD4J^E5f97q6s+Ccfz zl;{eb=4eppri1f=cmn84wT|;qU(A_E&} zhX|`IYjuY}leoMn0}x-DfQZBlknG#SA{jtYqy`iT*s~JGEG8i$$rzPV8d#jgo8OIC_LJpx%>0~6sWUu8qaD#^%8~nAJfx+iCDNbl$=4&MbyJkds;qMJu ze4>{;KGB!VdCk_w1$+B56McvALwCST67qCZk<3i$HJeo|g zNbkB?(Ooa39vloAaNn9Y&S%vj79|1^-oP3gC7;@^W$&mz8d){zX7N%Dr7HYN_=da3 z4dsk#=@AUFCbQrx|d#@6xQ35pC9dqVT*s=t5wi9K4mPIsV6W-Oyt+pbVnX+<|w!1*Sz* zo0uQEW6*MTWP*%97LI7Lexbd(unmrJ-93Wd+)#Lp$XEzXFeqvUx0K9WhUwow$2H$Q zF;8cgx3Dz1T-)sJ@29phj4)T^ATA{&B)~y$^MJcedHkR`>v)F{H?Z-)&0&u+uZM#- zvwcJ?;kEXqEJe|oL2(1Sms+cZ_w_JMYzqH6WDN^lSZ zSLH47?beV*au=AplaaUJxYZy=luXE4aQSi$lkN8_vl&TUWFKr8~CH{wD^QE~WkO=gr3(l5~xsC=G!3y+r;cwyZD`5zT)= z$X-J;F?T!}l-ca;|LIZ*4Nk`FrxTYAtu~xBowye?6#!*lfiFjEP|G4}W(!xPA}BNz z%G6pyLXWUM@r})V8e%4r4b!hjF_1pgQ_w$^>f~vqp9&j)C;^lPK4ZW=3O+Xd0(Z{$ zgfYO2YY}QB-4dAX*6ObG!WqqcSOaDBr)ff&HT8 zGTVdMJgqetZ5{D_;nu|xUkxO&vd@`adb)K$`OyNt^R43kWPLRhb< zVgkG=u`4_#dIoT6Aci{;dowbo?uzK$$?%z!m>fmw3Id6I-WZ3IF>Pg z_=vJKt(8?J4Eh9yUf7&PQ7ZzeyAr+8$<9>BsA^#~lqcF^3pDK3ja*wVRmapEu|#~J zE(6+-1LV*G9bt>nm5emx-|{H)?Y-~;vvN536#MlY=vC&qM|G?n@1yaXNy>Z zS~6fHRB`Ua!Gxn%o9V2@>VI{=zNd`-GllHW5Kcd3s#YvyT8T%Gxs9EBm_WCWR=qjK!#FS=D6@$ui}8QPMdvQqRKk zi+hX;Fa*Ksf3eT?4r1hTHouWT%?Q9nMlexOeRUY~H4ggPL`^E!WHKO^a&^1EZ{BMA z`=#y_GG`%|cLbMT;7;6o{H#tFmF(C@hYbP+wEE!~+=_D&nBp>Gs+LJ4!Wj~pVI>1@ zXSQ0cdQrw@2i9V*W=PcD4S67mk!00f$UFr63Xivraf-&$5+z~3hYL1Fmtpr49sDU* z*mnDeP3K7vu`Xj&TtcGbj_E)QZa8kR6jF|Nv$_2QGP5=%(Xpo_x^NuF$tC)aaww}x|S`?JkC~-LZ^X1_b(B3a@ z+_0QDdZ(moEb~J2@Kuvp{bObj7OJcdShm9zBWoXs`XmWE68?!i`u_7 zWWqSpWP{2OR-sW2vr(s1YLr+iVAJOQe!`HNhg8MH5}FSBSVxlM@M|w)7_5&v#P9m_ z6e-CbS2F1Ytqbsz$U0+Jm!71SA5W&I|2^=@aCYyVxm zv9DO`hDgYn)+)~-!HnPx9GZz>T9&QByS|i7YD#pJyi9IrumFhIO4iv$Q*plT$DPky zz;Y1zoV^^L%;g0epYp_6l%oOP;KVP9&CA>jwPZfx6j)N}Mu+Nr{wVQj{)*s;27_{9uMBLtHSUdJ)XccB>#JiXjd2@EMeEW)b~(N@kj{F{b(>C*c?e&ZjAF zX%snzuf)wc%h4maG&Oh1Dk$!?lfH4q)gL|K`yL9v;93uouk;B4&0i3EPO?_k4D|?g zj?$2@NtXool1T6^fvPfuv=$4(Osb?7HJF1=k=+p5%f%1d>reN;-F)(J|F0V`0mJsY zBz>b1YVWOs=CE{B51b}Gb%>%$lWZ@dW46@LZpdAdrB#Owd8Yp*qnK{1aO9wYJjl)w zH0QQOm*w9sok?si;k?QEzo$vQ3bk+%HYPRxij9SIf{Ku>l5hus?y6Z|bab+Ah;NVO zS+97o#R{vZZRw#R?xZv32;kw!)@p=JP7fzrt%xjKJEfdz9^)Vluwr?i;8$C{*iaNl zD9iekKil#qbX)E+#%nOoCx6+I&DL6q41@T=G$$q48wZJ_S2X$zBov&4cOi9=Y-~!- z0Al{QJkwR_WSYr=DqwrFl#RS%DA=8NS;Lx1XHz4z7D);&UHxb$k5=L`H}D(|g<$e^ z${`t1ka24irF)vj^ zzzFQq!yE|ZX{=Xw++$lrq^&`8zqY;tDJA#%XVBcSq@Kv_*s?^?f=r2Vuzq1F@>q0A zsD!d2IUP+7F^6bjUhV<=%xj!KD+cr=pW#LigbA@Cep3kQ8cq7V_UsVUQ_K*~7ze55 z{Znk4Nu{V`#;8jStB0iwF(U=0#^yvBqC~u$&(H6zu1+B%hA>ymdXwqt>ha`gwyKTy zUe3=(zd0MuB({QJ?u;>xjtAV4@ZEJ(_6*&^K2P$Ml$%9y*9wnj8}JMfQtz<=G@VT5 zJ&y1`C`<(hs(mQ?<%sws*WQgMNZ z9K!9jCzIm=sM{dV^7jk^B6TTnOQ6dYQ2tKFf7yZS+&THqYGT9M42&o?Fg8!;JNBtA zkS_6BqGzkCG`dpBJ9QeOx+li(o69#*6V}tC!@gk5@1=lR$OBOz1$mAjpPbe1TKCH%7Q|Pnwb*XtCv{G&F}|w;Pf^|5l6bHKje&v=`ESaOm@~Mj*Xad@Hj= zzj(I&SR|-iI1BoL7@77FpUg-ZR(W)fj$ZKFlB96TDlVoY2@*o`?{qRb9Syh@NjH*IlS+JEH!F?mU9$-QUNRzZ4FrhnVj}Ykljb1-Ae-S!On_KD zq7v39HU?fK4m#aM=4I=wKX-74l$@n?)nWCPvWhSUL0o}KE{`9Ky+H z8x4qr6twI7J@W>RpGt=%omFTJwf5mASSbPOuI9DECWY0Ph;<6x_h9HSH>-{*bMfxiSklRPDfL zXcF+C;u$9_yG+mU&oF@KEOOkmi7NOc6ozxY=BN}^rg_T)zz#COBpO+=za%yase9qw!oIx6v}ZM{lY7e zhnc#a--%#~@ggRwhr`^uiAOn)i${iY`z7|syDg}VmdStka zE=nBQJfo1jA8&rUy}tdQy@dBg zr6zugbYGuTrn!AJ>O)zMoS*R11IR1!8qYNWCakDMA#%?K^IhZiUFgtdD3Q1_pJ30K z3dRa_>?nr4{HGqNK~{iyJ1X5*PR}Qie-kch>$_Xql?L9t0^D8m0h>%C`?t^j^e3YK z1}=W-f&6CN`{+<#=}?KZkMMr}f(jiR`}@$_^Utuu=c^{rcl)8}b#5jlgY5@lbl&g(inG!SG#>E>y5E>fyFJ z)V^qP>VAuKxD2PkmFZs2{G?$07 zH$xts?Ut%4RN*I9xj7~%2|N+UIj*?rkijoryO=5nnxarelq?~1OzL&&2wl6@cQxQF z49YcY;y~+^zYBNF`!b@OT#8NbULPZ>a|{OpW4a%dWdqE$w0?_v^yfZ?g98?uZmdDZ z0AEQw$utrrKT-E!WYEEK!WXNie#+QEzB(8fcFkZPbd1^NClF_h^om-&eoWRuR9!2O z=Ye{O)hRBZN}b(~m6Me~O#Z2J{qf}!KT1tH7c+#+^IS;?^gVAH z5IV5;{4HuS3#aHLU@#k}r!L(jAB4=K;ZNpo%@HPxd=el8=hRB0*JV+emC|J(iJk)p zVdm2)E3el?#~hvB(^yk1)^hfQ;gi<}B_vKxfAfv2brkea^Nl=))?>ek6%%MaCDb8V zEAgx$_)n#3p#W zz_M{M1+s&NnP1e508wbl0@U&m3E6vq(F?=8@mYt zvymmlj&brr7cFq|G^m3zRD#^_WI-{|?rI^N&ai81BFW0ihE!0ss{W>ecJ0}Fin+$$ zA7Q=SG~zgAqk4hEB%sSE+5~M0_|9&@=t9A-YV1=p`p8(Rjp_N#-fB7V`AvfPd>j+~ zzG{R!FwORlyYTb_b`2GRB-TGfm3O|tuj+x_FAF5K1rM=+`I>X57 z@#|CrKi@0j@E^-g-i-fBjWVREs3BUT!p#BYK$?Iup$nL^gMS)C0=0naa}o7c>7mG) zu?ArU8N)leyQsRZfzdP1*}z~I`xb!#!e>L(SlL4y38hsWx7KTYxWopr43r0}z$LP#$v|RU=t#woI|w5a^6;8~92JfJQ#oj5j5^`GR)RTg4NQ z;3-V}*wg49Efsgy?tF?np4RSsR%{QCCdJOY-zy$WFa80aQaADAI~>-I@R63N)iIb$ zY5*WGNzuas5fY2_F<;N%RZ7-^0LB1Oo)#? zKko@R*Lrt*Yq~DdqR=>CLl&QmQ~;WVf0Q-~aWTMcs<>{axAq4U%doVeB+g*q1->tA z6IO}IOg62aS(<;Joeu`bxKDg-%`(z7{Ax6SD-`D2^0#d)iKV5xP{HGrB>|C(JmobB&r_A_l#mO%vR_ zq=wf-O;HUg+jbhd-2TM+Iph?{7;}kALbMd0daDIYoj{$IB2vr>D(j2BQFfFk z$6Nkh`Gh#z!OZUbpl&7RNo%#5OiWS{>Z>HxaV-a6^7GY13Q?WV0#P@|MxoAysHQwv zfJ65HT?pb_3+7WPv&;=wY;hjoGFn(P`gV}Jklo7zaH#BT9^AppqTvOXch`EK*~C&E ze5RrXPpyM5L7rkf(}7}+B;aK55Ogl}ml2=jYix?cBL_JowqWh3cF~%gyNHQkc#L?P;NxO@a1Ni9xy^p8 z1n|LHod$sxq@-`#g0du%IVWQ48MHs{%;D8RP45!B(AdC7TZ%p9p6G44yeLwb=-QIA z5$B59rUOhA4|aC4k(Xs2&qzp&XPGj*@uS(S3k>tF*Qu9hVUUPoQ;;YMkr&}aZ}gD$ zU)p#CAB19Z5nY3&3-vpW8I{2+Awm;05bM~+rB7#`KEaJc!};Ys9F9+)UGTAjL_6;v zJ!S{ecM-V-0H$Fqbzw2Q6^OAn4I370>zpZR&%#C_H;(&oDa!z6!_kwqQbMUOR{}4W zY3fa3N)B7me>8MdKEAWTbPi|6`nUT2PKGZvxk^`4EwVnMz8vi2Dr{9)Cz%qG2}~Kh z6ocU9^{ikj<&uc%pGtbQ8P+F*9jGaFVQ!)sTcnWT_>YbWhyjHy)fuUR3YdP=c>;!@ zwcp|t-A_DMfdn|cfscuN%rFT#=5Q6Ljh-}By+n#0L zA-6aQ`S4YQpk-Z>4oP*|zEek)x{})UXBfk-Hu|^d&y9`xTUVe3TyhI)fGPhaGYc%Y zvJ15!(MdlC#}HxNB{;m}J4pn$?EKW{uc-0jZb?KDLU72m^L#Ff5tbhgUc(70#l}0mTW?iFV zj-1x8GCoR&oQ0a?6P3UQIxY`oX?PRSBg8J0rcWVT*Lt60S&Go2FMAre4wm5_Il#0Q zC!|CPn`3P1ona+0Q=d2seAkD=*w|c}>YYM^d7m_M2q&@_m8b-uilyK|>2*@hLU%0{ zNFt%Oqt5cS;MJx@pLT&4aFEk19Xr5xu&76yw@kMy;Rs(bk+1dc@XsGVceaDbcIB<4 z76Q>)FS1LCKf1z-7H!0`z5xBA1`-~b3Vak&9^>R3snLyEg&giG_*L=2<*IhW8%sm} zLw|_TrtyqZGriYFbkzUx|4^}{t^mhHFeU;684II9a3a5PJ_vR(hrlQR!^&jz+CrQ- z3w|Ts9K|P=3#~k3D^Il*Z9s&5gQ`J7vQQ1c3{cJRN+4DK2x3Y|^d>UN?#%`=Rf68| z?*(^vtQ_1M=trTh0ncw*Z;oM*OxkM{hvdi9;GV??ZbdmT`UmLLd`yR_tva>xoOikC-Jw~LY!#@<|Do%pQf=0%85&{l^{QKbb zE!;?ttcJiky?R!ljL@-XKKT|aHe|}suhS8Ee=T1st3?f!W$0*GY-`rMu$jJ$Ulhl& zXnd=`8x}@uu@ow0fpCUhvm+}%M%w%oWPn*mI*S$5ZH`x{#&n%Ha zhtP1mc(!!Xa=NJ@@uyb-l|>g^I#$cNmSS*9caE?eSt_qt|fu|_u z>o^u?e=INcWVz=SS%4*{BG_-FuOm3g&K4w#pU{mPL1pjjN*%z51I!yR_zhsw9KtQh zjZIv=!03b1G;pBD+86HRZF54+%+v@hjbS(@dBT||;3Zc;7r7kSDGZU5__o7OsHP!f z$keD1yQOfcaQ_KbfpyLCWcpOTqn2*xhr!{i;d~bgzg%r5&T(v8+Mz4H<$x4**(8EC z|I_V!H~Gh+Dv-Rm{Ml?#@w3_D(p!rPZ&Chtd}B$aV+jk8q?j3CtieHp*MlkoLTCf2 z-@)%60aOpCFq)u*u5mwo=tnp%{g?!^WL8N12J8T$KBKnQh-y!D{VR4%D|f zG%(f`HGnoZ{@4mf1&W0g&q*YlhoBwXX&3AA=Ei@l{Gr+glqxvyL<3B&GufX9BTQ%N z;Nx8GGBerV!G(w?(@!x)IhBmD&yR%AobV0~AYE$eS6aeQpRNS351QHLjz)D6yF=KY z#3HFLQ!bVqeOyM<#WqIo&cPB{AE%JOQ-PPiN%ObLxv7Huw%1$x?LlR>h;An3B&~)G z$S$0dZ|i~;)kyaQVm8zWvzF7D3um*Yw4+d1ah-=_rgW!L+Z_P!7}`U!6{lc;F;9!Z zSCe5loT?(}<&6Xkmek+*ebk{{cqyE)Abo-E*lcySBPX z9{B#W41jJ*Npnuo&QP%P`)i@x61K0~ts+g43dj&|1h0 zMgm?x-4FeS+<-GTgP#UR7ua4aPlz02=qPg6M8gu5$<)|LnmigWt@{ck$Vn~rPB!Wy za6$u<741oIh-@)UDR7cFih|)}+!fD8Yav#cp+OoJywP%bZ%6{BpysHBEqS8Go1rTy zqUw}(7byIwr!QWku8SQ8Tj8@Al`F8}oHs2}*o@(^B}O`IP~d>>h@wYN4VuwL`A~|g z1C|YgeV0&LFy27DdMRQTN(2WHr;-p8Q4F>^1EFEj8;%` zz`KON9S?E4v25Sde5-DCsAUN816XIac_4a??*^FMAQiCFP)Y**u`IAe)ms2F$RrdK z=(k(gL!u7C2bG09P!#HX3Ovp@{*Vnm1%Vj+Xkpxsh{$$4rVy=$okzbTc$-+LyQ}}T zayDC8mBv0 zlpH%>L8o3ZoeaM>l@5{l7&sz>o>&u9qvOr`qQW5aCHHsWW+?e%PGyB4TN!iYWrg&z z6P&7Q*%V+2R~J5Ebqr>GhO>Jw`_px9zm&VjiH*q;l@X@tY%3ZqNvBv#a2d34XujRy z%1YM7JZBj&`t9Au*#QA1D#`Uffw9)*hL!{EFWsvEOhkJo*;R*x1qmk}ay_S} z2Y4oboM!i!T|v+l)j`6Ncy##yhN6%llr84clA)7d0UoF-^?={JW_StM za#-kOk7@L}6-KWjq$*5HZL3_%nkH>wo+EFEOJ<2A6k;buQm(h^-$=)-!b6)u2;a?G zFs~iyBZi&N8Wd42z(^UipD{|z#I{RUV-Su+?&wuM54D2?Wsu%u#7Gg+1cDLj7PsZ&?AlS8%##}a^`5r)7*IK# zI}VH#Sz9^)DEQNkcm22w2#4uBDrh)TDVh!KB_tz9-G2&@V?>Tc|V~N z7lJG9t7fx8;}HFcK79y<(!${7ZqIy+#6i-{gj;f?o-9V65eu;f$I`8;u!Pp1# zhYXe21Yp1jl>;$+tIwa$Zfh6>9k#`iA?Q35b@h8B*ble9Yk|6KH8qrm47A@guR6BX ztjoY9&0hgN1IMWS+v@|(1@MNA*oZ=!?H>3+4cmhP!{>)`H8u(KUDqX1u;xwfX@t$+ zqriqL4=9J0%uBt;Xd`dm@kAP@=u<~?m^BqvR)zV?njU~gCh+= zsLtN7Sjrv4jNzh|Eo|{4T#Fj<>93Gtj7U{by`;b{xLDtS;|pA<(cT2_me0p=S+#>f>rXfY;f0u=V80`nOx#yBiNRNK3uFJz^cvv9&Jy zQEt;gLsspp=goSag-Ee}M~|g4EYsVEaWIB$@n|3gyV4!FX^4+LpTxAm#TRYVSVuDR zU=#fLK|%V0!B!2MWs@xAI3TNpIp9OGiB_w%SQ|!&K#64VG;LNA^;J@hl_V2B7$?=} zjNBmcNy=1Si4jyoP?sI?Xe#gp7$3t8(k%8HBahMUhO=&}7^O?MQ5^8#pw9=wh%-`Vr89O>= zIHM6SW=%^_1%?2XF-?EKb+4w|AskRo`S8(UnFL-oNIibFAq=JBx-B?dpw}{Bg#C3m zraqgFo=IpfiP8*Baga{sp&WvJ4UT$m;Bx%tRKoB51|Nmrynf^FxBgrEgz(iRx|1$t zD=okLWkh~V^;Y~oF%MP%#T@~nS@=c<*5d*_ypD|sCK#e4Zq1%!#ABm9W5NgdkIC zoR^?Zp2^g_E(UWET?mkefHGj{dIagsb%wCE&`u0r`uw}!`Cuy%Suyfwr3gQ{uvEgJ zagEf)8X(x7V4>@iXL(ldz8M^fzdrW9sS@FI@QMc0SVG8SgmAQpJr63GCS;ucab=;T zOPG**ANDhxTUPq68@^IUp34pwk4&!?|IxeC`>a5WTli9*4yL*~I2sHQa83Qp`HmVm zh9{#5bXfZ?KafztRB@ZDgRgO6(mmMy=LN4$!g@^Vhp`V$F0nMK zH?^(S3XV|S#7ctUW}e?v>OiR0?(>_BTe|Y&Y}F!7te%Wlbyc&T<_vP2)OL>uU_};8FRinXw}zT_Rtz7mmxY2=kn+7=f3# z4uP|8aD^7QVf_{nLX&i((L$rGXyallfbF$boeqhw>@{>}~wc8JRMdfrPc- z3JZqy=ydBTopu_sonqHMvYlh`)0pdgs38t(43Wk&Y)nKsR0j<{W+2)OqRTOSQ(?tz zNJ7@rg$~6zS-Q#zDU4mlOTVFGDs}= zz;G_BrTYZN!V*IYL7{i!%DTL0B{eSybwvVEhVb@x9irxMZ|Q-x>t2DnP$%QXL{2B?+ z(aAb2>}3{@O)|en(Sk9!e+us*?6nvTldz##L8Nj!jISUgBtxX){T}|PX3W`6qPBsq z&?98D7;bOPWQU*~z`eyfQA;;|AWWQWEf|e8n$^tCBSzLlZs=r|V4ZVo@3x*X5 z#d;O|yr2e^i2{Ry%XON=E{!d;ywas=G{E{udcd^=+pC#bNn_Z47#?Gn4QmGt?-8x2 z)wNg7AmTz+F^qXbqCiX#*bwRT#Tk`nrEr15-yTlRu;IV03onWo(iAQ~Q|!xmIurz- z-6+@3PvtM{g_`2EHPG5y6^GWn$l$UpkEO3Y?`BjZ)>lf?jzNdDDtw4+Q_^}Q_GB*o zD~*RqBEBn@;ybnN_z{`Nq%g(S60{!{D+@BDb;V){K>VFQV%2rG_eUI#yYo3-KJDH0 z@Qs*iu z+=2qkc_F9#@|g!;V#rljs#Fx)#F}aqJ=@vX-}%q)zTM(+KpO@xp5q_cwPg!J$Z2tb zYDasZ4T|AG`j$D)<-hMM7iO?vv=xf1M3(%urD7&TzkwUg+;g{%*qeMlc6cH16uI(5 zcd-6S`0K4=%Sii!Yhq@@Y;Vdb{)RN^mLf)p@gdqBUr-ZO`1*X~c+@63k{_ZDe=yYLJ}P>q$MUJJn}%AsC#j z<0{g_A$)BZO}j4x12|=u5V{3+;kX%gAudK@QubhKxZUTte-002Q9HmZNzYL-ZP?s~ zotp7p#6ulhWUw<3{(Y3y?%Y$axB7FnqFU{6oF zXJ{xR^(yEWIU`ou9lf|m6h~5<;+&Eq8yp@DXCf8l6509aVdEgFD>iKS2HMSN%`;nV zzDM3;VE`nHaXv8lZ(unC8O=+|c+_n06a1c-WL5ij-!bp`2h5$}sBLV7wW%gJ+r(1GrB{`7VI)tBGKcemLb&ladHJAHS zp`_4(k1g>D1z3KcU+9C(#_tMa$B!U{OgQ4+%AaL89|(|kn|Y`d1r}Cpt1`rPYo+Qi zX0CC(Qe+#;3ZY5g{R6P%;7`O;&Q%)NJR2NHBuPs8bu!@pVLoW52_o+?d@ylc9qPEX78D zHc7IY(gLzUg+5RviP`903s>*QmWn5BhGI$IuwSeF%Nl0q2u!5)79yB@*Hj=-+LXcg zuasvo>RF2lJ-%V?vWLDHiQ4o4$cc1Estyhd=Q=I7O{-35NvXxEC8-zfT5V1F3jUQS zoF$E0D_0vnn5~=thA_HZ2sT`NY+yO}Y%$^Y={$TM;m&+yeaIVv)@!4<0{z zxUplzXM>nf_z4f6!2=K1H_-`PnhipwFw;ez`v6LIrx7Om;X0@b+Q;senMU(m0xfz| z=^rllvnF{EYkWF?nHQ2(lMt4$o)3@NwxQO{a7oOWUc&T$2U7$o`}+m#DRbUGdWvo2 z`O7n40q&Z=+lUhF~DY?*@3O&u>W$T0%f!sW3h+6 zZsDSKq`>fNeUM&U4-l0oS|gg5m)K6swusR~M-Q6ZLe$Pvcpd>kFKIGfjzq&90&Yz# z#-$x&k?oH!%6-EAo_0VD+&MzPTRNohRrg#{63{l*z2tm26ys; zJSR}Uaz_wI!IB9VF13K=8ueq*4ebn*0bG3U_I}^{Tu@SSvw-SYB>*Yl#AO;mU-`D>3TVSfh2 zY3yJ|Pc)uqfIszQG^#BsinmWL&JG9DcN|RUKK)C+=)d&>_s_yGHC;h$A^^bK1DF9M zfRnE{1Tettf`F36Bl^p-SuE1@`b$utkS-Q+xZM=ZAq;#1zHecmm}G=M=`LF970}1c~N7bgpA@2_w?IS8SeOj6Aoj zjUd{g>>Ge^#D+WPWDGRhd1>|l;m{7Gj|hpF_0S{$bTdJ{<7dH>dIrb&cqIfcmS-Au zksx5bT8B{QC1B@b93InEh_mzEfL;!3;Kn`N6?|pT^fFg24RNN3p+akr62M;3U6)&5 znXw@c7vMBP%OYHRB!t?8J}M+09DD)J5R(aQ$!;|wg@HQ}_K*&v3`7G9d+F-Q;_ai@ zI7nlvmFL#~(t&up$5x3rAK#uVgAX_{9#He2BOt9X4G@tILJFN~=t{u|F71W$`fLTW z>6JT(Ys{Piac?>AMQ*__dYzx+4ca# z1~b3?z3+P+s_N;dg^0apzaKW&OsszDv}&Dd)v8siUT`;b`hqeOB9IULLd+oo5bfSR zjZxVtZV2nn@TJIGjqFl*@!-U&F#DA+C^gX^@{SeG(t>@A%ID3nRl0j2R1C8aAbD<4pr%d!gPj}yF`P%bZ=b}!1=1|Gs3 zpCB3m>l+p;t_c>}??~rGxZA-IT6@)5Xmz(fK^6&fpw3not=A%{mT!<3mL$A^h5SyO ziV1|b=sn)GA0VRfy^+!=LIW04C7(G8NOth_30;54_o_7=c{bh*zQM$p+VGatJ;_+L z;B{qG$A9ek9To}OV0KnzbbEnT>}R)bG^-cE7!YId5l(B4P6Yq@I9EGa#^QfLtWU!G_@D?Q2lFzO|hP}({me3;$+XVrgX5s##IDE(U5|F zlmg>Z@V2G}LM0V>2bI}$(@KUp?*$Ss;)xrLM5}GqjP?HnQKgC6qV6%5SvS0?DG@NG zrBbV$FqP*COrXx|JlG%`|JMi%9mIDt$S*Zkj4L672=Wual~UrHa^lBDu-u&O!iRGK z65DOj1TieG7#?g<0RG7G8l55SkS+5xxvP$lrivDPa(T}2Hr7&`Erxsib8U>OuLWzP zl$F2wN97SoU`GwI_ie=dR&!_9?Vg(kCg-uvSK*Dy-;zLmyleXQvWln(A zT1RKH0bB<5LLZuNn?Jylj@HNM5$0pDe5my8U!Q#aFwVQHO5fI%o^3wde7v^U6Z4^E zPZ5sM8SQCZ=j+GcQ{{K6d|g-hVdEk1QFp5RkX1ZT7F7!LU_3fM5O0tFRHx+CPu|}) zUz$vTw*1r)YS2FtCq4GA;r%zv0rs*nI=Q z;fq@;Z;tUl=XMd4sxe1H3PX_M+OiBboEZVlTNIw(m0h$w$__rO80 zff2r?$<`6(=nHASCGf+HKZ!^}PKKiGstEO%YaLYc zpa#HT#rQa;$K6$EJ9v-4FAfH&z}3!@C)lvDGq$GU53xJOw%I~k3_<6c-U&DC_=hp5 zv!Z8EFoJ$8^L-#dnGxx0m>iMz)$^kRFg~U#!Rb&F#ALe72PI$GV7R7LmP4E9J_4qS zQW@jnAZ+%kI!1r(*{YDEx)=5o?_#H|98T{zhGQlE)4SGp@=0sj;A>SLv8vMDPNlKQ zuhqz|KI_)P1lo$}N42qHhR)pVC~K^_LCx99pf>*?tk zjvjb`z3@$%c-16O?3w8LG`Mn=Y#?)PZCAVv*}$Rmfxs&eSuFqpW0mixObDpHdGZY6 z-9gjIAO45b2asBucBf}YmMQ)GhUVvA zWH1~cT?)g{N(9CB8F~GR*Tt1cq#ye6>Fn?wgMhro_L&#&PoS*n`z-QY3Xe4#=y_oRKy$RZ6_{lxp_di>pFbyZ6$oX z1y6idY6;w_Y{7BLMWhQIKJ_BR!LLYKUE)Z?55Vt`MMKW0 zR1f=`{L3M#EAlwWUD;WolD?uM8aO^ITyyQbhF%ampNuIs93i`r!C&9$kTLH{0C+(r zr%(x`^F_)iuVpzKL_005yh7!vL4SV}r?OlwoIUDIB#E82mZ zpa49Q{&yvk{x=bz4xxMU<~Stxdm6nNPJazLuMc5I1djG*Rb8PNV1#!()o#V?ITZ@reb@4CBDR{ z-%a+XV|Dr+wo#j~%oLe%lYG3-ggW1iPj2$Rs`C`vSIkLK%l6^$90zkZpXxu>^4Z_N z{i}jwQ~|%tpRZprD!x9&GW%@uGAcctq38HfVFxu0515S=YajacIbQfXwGVvH;@PXo z#F}qH>7vEnk84hd7&8mhYIAnJ_lkcZ{(X*z%g%-?H^p2C!p8OynOQASv0odndBOKi zh&Q=$!)+nfrU4E%scXi4aTXWqppr?z7MnbWu-aD7tU7E~lC0FZIR&LKg4nq%*R6~q)vxx zR*~Eoj@ftYS#=nzp$q%U3pM6pFfHMho>z(7Ui+*TkFyo7Y5-!GKOmt{}geX{r zqDQbewgPhw=v{9pY~;zVMX7t2wxFUD0to}v(m5%DVr-!)IC_G-;dushgJTx$gafYI z>}4^G#+MOffk2)@#f(h%?FR#AJjVs(=NXVg1rnIBBPGrl|42snexRxyFQ$2kyfp7M z1KZWY`q!l)RQzLn{t$mKO2_*Ifi_f=N3i<{%)^T9WI=@f=_$?_M5@S+36xZ6?yzPV zJveCHr@z7XUQF?&{`XHG*k3hn)VcnF_I_Ppup@jQD;Z;UN||uQ!4g4Oh#nJg-lR28 zR*MG;6pp3s8a4y2V&dooO-6k6vqCqR=oEVo;i7|44oecK%GMnV0|Vqe)mSwLRbS1x zEapF_k%hZeaIvgRn!oVRE9*p{>5T?b)!6IV@L7`Gc`;aE@Renky?%QMzj4&Wv+C~L z)mEVzjdkc`VTJ^t4$lYd?0|u}BdTiU=&atqZ}9$$=HiZqQC+s5sXAjHH3#!I|6xKl zIWSJ77pj4bsR&b?2Y{M(gF-fGr-~1LDY^qTt9E<0+z|BB`E;MRdW&tE z?tdNuQx$wVg>V|pt1*}3d)InB+`E9hUNQ0ZOQhqYH1y^&O!p>u?G#JlO=aQkkmUa# zsAc@Y$MNd&edWr3=jz_&rXGBKlwW=ZOW1jM4SCP1--R)V!nfcnYJ3z<*FBFi@-yNw z>RzaYijvyGalw7w>wey?^D`!m-3_m&H3SP#aI|!$y8+e2D8Xb{l*p}1$$$F6%{QXS}t;WL!PfVlw6g z0+5J?q5Y?qE$pv5pQfdpbA2JrK|dfeO+WHQj98DZ515saNjoBwuBCHS3|izg_asQR zu^GQcWH|Gm&{U5MjY!`+J)IqM59Ax9+*M5Hp0|%G%Fa%G2p$oylnq36xS9j^RPl6^ zS%nV#_#tl+d|(^CrEvF+`7F6z!m|wipmrBxlFX`Ky9-Dwlf05Na+lA+yY2zdN=7`X z5F7H3st@vqlgVlpDg}>J!zco=XApkB%n+=1;Q-5N;fTJ(Jgny8FrY+xo#PfC3A+{d zK5&exu>F{}VkFj8$nv%EQDaPSiDE7W@6v22J8_#lKn~$t| z2UA`!SDO@wUidD@biGZ*WaaF(!)lR;4c+Qa*M(`o6>s=f`+QU%8 zz+6aX6`5A*RprrS$gtnh@$3y1?BD||pF6mKb9?Xw)?6kc!PrIR-iEH_(b?P_PRNqx z!EgvL#Uccn?CU|0F$2hT`$o9c%&DH@tH;biOMRvhiY{N%{UPY-h0r$V|2jy%_*r5$ z7EZl85z4M7-Q;`1iRompf6h1KOm6b60gD91Vc>Mum5-&C1j3|4%qfWQj|G!h;2>F~ zr{6R=Lf)*-Eg+WBsMgkkztO98DI8MbT@I^VdVpZ8VUDmQcSf=%e=rac!&CxBsvx$O zR9j;d4-7N}~==Ns6->^o%vp<*A5T<5DxZfpeqX(HPn| zP(lXZ50gVb#SIEzrt7ld>Q*7GLMJ=nzp6A)ny9iG4F9nkaK0?W=ah1O&^qd(M7;M5 zC8R9tBRgy9!>+W1Eb?sLCo@*Ty&gU`$@s4GQ&0gx38*ffW?3nWCk)WnymOZbzqL@n&miAiSzFN>0eqaHvEj7w+iVW3pOsfF{(oImv% z#*ow2^?dY+|DxMXm}y$>@#e%SGK!taBHO+SUFc8q&Z&KLHRqU@KnKVKj^Hj}2=Pj% zXUU}AExN3+IG4SKRT87XjMp11Sc!PshbK5MU!CE9@usTGHl#5^g_lLlN}sP7^UXK= zj;46rj;b-{NO3m)D{SWNI{JLUW8R>--zU{7wS^uyP-m1yS34_Jrb$OYV|{9vpn&QNlEg)&jJ{#a+ILgf)i7Ob<#oeFijWLWbo$LD=(3rgY#GaQvD{dHw6Xr| z&pY3&|MlU2Lef67H4yzi#Mu^&ZXD3XdwY7qh3`xQ3dS1oZQ!_8#K+T!uXyxX!M!9W zF8^UsMTf=`V;sIh9QPqRsEU|aj^J?Z!+WS>y8>V7@h=wGu(g7lhm2XkI{Zq>Z+3Cv zcy`23dZQZueKXxZQ#zbilc>al16FxsUu^pipw?bZu=Rkze|K(&g>m>Nu8y6x*pKKs z>eTY|O<1{eFTK!FXR|2cg~q+k+f8_z?hNX1XZ3tTeoiaQXkSD%EgjpmpV zIs)PfYp^+T6mgq+Yo&j@mvf2Zo&b_eetl3(S+i_xOj54}rwmhswlQ1qAoFYJ;nXfY z_R6vzyDMG|p+Wf=77kPf7&F`_I8+xWPmUSstrv}ScN?~SY#-T_{|cD;1>@F0U2=R> z0B3bM`#{5Eu=ix2XI_iyViDfW3HQI!nic)&6{XbSDY#v32oY5fY&BR{nuCH{fttwt zR{;;kw%+l~=;f!t8@AleBB%m)O7#{HwN7v)IV6A&;kqpJ-FB%BInB;lmGB?an8!$@ zgQd50%bpDv$xxJCQZSU#X~#ZT&Lle3{<7uWXHOsh>7!7)`a7NXoRn%>v*XRwtn0^O zuHNsq)n-w#@;G5t28B*1cxs2oYKZq@;@g;&Mvrz~+ zgLjh(;b<#p1#GhR&N9%v#?I3HSK1{l1H|K_F%`Q#6Tg0OF0eO7E1UNh;sfjViPMxC z+)rGPy2U?sFvnFkig=LKVTwc-iO9M-jzhg{v&c408xY=bn=MFBJtc>L^f^45=n}g3 zCB*Es3cYcJ5={aGS2^|&+b@Cy2Cd?KtTgSX=;)`Gc-KtP=WP!j_G2z($ zl3c1M^)$pMGivS0=`)MdJ-}J<36{a>`SCFg=`g>rtj!L_b=VU2|NDMqV|$!xwvEF3 zsK4eCs;VgQ!kaxj>44Z#l3AxbKC?+YNu|}1bK1j8=N&t^+J>@uqkj+{`UrbL8TqO2 z!G`ElxmA@^09!%2y0mA&?FVipih*CD&Dpmzi_Sbz$vDPw(wR*1ZaH3UmDbeAU8jvaV1?m0FPg2DDi!OfQ*XL>LjNws@4&%=^y~UIu;BZb%5biee)bOM)2H$TOSIJAyNZn0ni&? z8$H~Ow&KabAtrIk(U52{YCaI4GI~19U(a zBVwnv9p0Usy_q0CQozKNg`<}v?q`sG3}K5?#I~YS-}8YJJAJjpRO~B+Z12Z#2k2ct z=LT^$t#x{x@=Ly;hGUzDW7i9mC+7NvcMI)r?@YLTdZfv z0(w6r1ibK3cbH5jSPl@DDV@j1$Yh68y8nVAX?CV%9?hDuuvxCO#?P>LeTmjCHEo=Z z;D9Z^;j^xw6usOyJ@lneOpfP$#pH}Ge@jG5#04S3rOwHY4uV|WGzMam^Dgm99={m67RNUc{f7~q5>4W~W;T3gI6Hns@`ULNlB4Up{3# zkK2$vm2~rx=)JHGG(P-3r#Pt?Ur-ND9bBjMmx{U&brzY1f%{$9F})rxfN}xHbFlAb z`!rmV6?&;iY&4YVID!`3;|+9b={m(6M@{`@%FwnG|5p`ZwU_vaMe{$P3vK^d?Q21l zMQwPcgY6y}`sdr!NTEa~zO%{L}^V))HdzswIfN{>7N>t0Xlzi#CF9mGr5Q%qkI z8#VLjtUMHvX$O)H8p#D>vwv~(y^(j!$~h7(vW+E2R>k;fc+Vz^5SV4{iojiBx2xcC zho^S_b>=RWtjWhNY^g&vD}azZHd_YfMGDJ_*$$ZGTPDkRK@(1SP^UeW;m*wt84-dQ z&@Dl3o_;NZ`je0wgDsrM`23a)qM2H}G!MM}rXs_nEp(3?kvB+z&j{$-Yf%C6{)Mx+BpE%ZyjUK~X7me--t8-=Xx$x?oRV3$S=Soa5PArXKSQ%;6PcM9*=m2g(nx z@!xdL=PhdY=S_1pM{o2^+O8UD(XbVo?J3C?cGYAj#ET&E3a?;zF9;ICqhoZ!;F2iZ zf#aYNdP4q@Q#~c4@Y@ELsjJ9$8t2=?*)Dd>SSd|bc#vSurv?n&X6X4o0(0{Hx4%y( zZ&IrQ2BW4X1RoRzXuzNusog#NBa9)m9X^8TxeZjv6Q^2Dsh{LvMQ5yfDsXw&VAt$= zGM8ry_IY|Z-kad13%V2CIdF6Wyi%>xA%`SI2n9hviO@t8O<2zK5kQc=PRbv2Lk;iT z9Qgm4HBfXbR0@2XxPy{V<9JE_L%1+;p3Y0y{d&{NezNNIUCEkrJy^Kn+;q^L%^o3Z z(HXQ8l3`TL>R5tdIiEB&fGhL5Nm9!c){PXnTOj8v;wj+BF#fA1h4c^ZukQ+9Pm+!g z@XD}(!JSHeG#bTp!3c2gF{tU*;AbNi32);vB%{i*B`SEev0T?EaB%{8j7qRf_fK573P zCyY6hAt`}H$#GT9fts1~5b?pUHp#6OBjGJ%Vn43Ce#gLarc8 zOcR4MeNtkm@)uMs6>+i#a?Z5=+OA$fg>R9&4?(x{bqjW^j7a-k7la_lL?*|Q+B&|N;Hm_>@S>dvU>h;&u6@cYyW`%*(2*mAc1!N33 z%{v^7@)=l!v~!Mvk%jfcMc;H7*8Rqi6N>0w~SHC%~8C@viWL;S7-7A5CuFf z#}*dpydekZVBa1O?u>qGH$NaP^c0S9Cab`OHweKr`a+tJ^WEKUX!ip~;r%#7cwjnj zX6J|d*u|q2WG+(-mE&GZs%cqYC%h+Jj%Eb}9<2vH_?R1S3N2cX=oMBn*zyQQ7V}Nw zp($1MuZ;1npqnU?nkVT9ceU7lORSb?!lPO|Ii}Zb@XvogN0)8mr5n#vssO?)-Fh*>RorqiTjNc5!b_;TkGW=1| zQ5OWO!})SW96a{Fo{?I3vJ46zIoV7w{pzW!3Wh=98LGotDj_ylRP!X057yG6)@GNs zDekVqU|P%6b=)Bd4l(*ZU;4#GH)yd6PIHe!pz2^C3V`SBLSQ^}2QQEW!m)g~U2V7R z=*zvAOwYY-0-$!aZEQE|k}c5_wW8pwY;9o#OBu`N9GmiDy8RcXYyF z#X`3Nc;8ktMl!LHy6bfQgRK(t$SMY&VNh6UUdfH7fmvWHj^WJFULlHA@lzG0ZRxQ{zeEYe5zp= z4ftLX<;htiPVGSV(-~YeZc5Nbnx56RfgyS82ddlKHmB#c;RTZgDX1-`53{5?kM~6)!ES@o>e_lQi)?{ zP`J^m?r^69&K^w6-m#RfLvM((;iHqsvi%RIe2Xn5jYPy-(BXe`6FFAH4#fcRV?H~-aBtjPhS0$dtdSRvpu;d@~7J8zFSG#fBzc|c()NN0{ z!Ehusi56?s>5}?ARykW!5YZ3^8xb!T)^4xv=yXW=-@Y2kqart>Wn^h;g#=ur+xQT% zJTP(iL^6=FhT9WJa$I-GHHR$xOmB?>T$l_OiubMB0&lpUT}e)t^tC9G(U&oA(;3KN z(8@PEMwUvcKwN@5MaoKFvdPN5$Y`dBu4GJd*HkG$8RD^BGQL1}pWpq>=rg2;2alG- z6*4Ystf5PakdeXlnHv8VO-Uk-WkSY9*!%sR^~=yf_SoqVBcHq-4IawCuJkgmm}(os z{&>xjk%@zUp2Kjq2ZS*Y$c@GMEFIC#(BMk=Jhgi{oV><0+6FJFF~_^}VZ#HaEbn&Y zjh&|IZt6FbOP$C1%@{3nEFYw(;kHHpFgafTEZ2Vwmr`R9wOJZ1J%e&^N--LqFDj=m@(O51CVh;y0ZyjtqgW zJeU!ad9GdI{_#gYp$b3d^3b7OZ@hA2iHNhhUa*^^C zGBB)@SJ*VQ%q%o<)C5@Rhr%I~ZNC#~faIcFM>?wE>(#i19OF6fUw|veUb5I|R)jqdjot zI+MD=K|qU(J)^y(^+ZYqy|O%{JFttTx{PJRJ+m7KFMk3%)(JUyhWtqP2CvS}PUiP+ z-`+n(Zld|<;O*JLXm@b)&3Xt7B{Y`31zaDXJ zFyJjdV}w+zW_;*-vv6Bgvl^0irp`OyG^r7k@EmrYtRx7OU8zmeEwPY#nQ(z!aAb-R zT_1J_=%h?Q^j){cJrBr9NZBn1L#G~eVh9@ASS5|L87LG9Opa*Nc{zwgZ2=pe-gY`n zX!%DNiPj#PfF-^t=d&1ugM>SKIN^O?EB?3l2BgBhK~UhH5hBbcaHd@CO(YAfD>kV6 z(PkcfVb5&Ts|#&I9bKVH+m^mdG>sNj(4R{t;l4=toCpja@Q5UANBQtFvRBZoNqt&) z+gI&LR|JCRFD;eRJ-m~BaLc6=IZw<*)0ND~L-rQZ_#c(b#du$NXlm4ZhkE~ciFzhA zw;G1gw`CoN`Q5azkJ+Rv??mi{vhIN!jt4fBa7Lt7tR0+#R@CdU|&BXfdsvqjGfUd?ed&7 zcWH}pzEK5;YIq1dEP#*Zt`94Lf?p*wX?Gn9og1mtCd3ACm( zOKD-uSZ`YeQp0a^z&dZ&)gXYzo}j}54ayAKSy&%mQ2{SLtDwR>3F9wCpTa?8BmUqA zhvmK->s$WbqN!p6{t{+=5H3fI zkBzl`NuU;+@t>N8{p<(xxgh44HCe6?;@0!Rv`kYg9ZjUpksLZ}!7F75Ez4vj5!%_B z#4J6_UuyiZzw`YG{cZDp=_AVg0q z$>};1m;awy9KHJ`674qD1C-TekJlXAziA5*CgkMl< z6@aNrk{NpN|-;g+ZhLNFiPyA>QI*x@pL9JU=Q(cHuu;EYxAhspRyzEw5Hqkdz&m}MRkI`b{n z_0i;L2DZiJX!wh9*aAuB6>~F0J5ZWa)l-2>LbabHTa*{ZO5776>DjDNvawn7VXcRXk)jS0BZh?t=wAqkth+1b%E^J(oj|`%SoM+vcC1W1e$`bH9Tv>{Bg#f-VZF3gU#lP00SDm;Bmxq-{7tl0%+U~{K5K=0_f+RPwbv1@{Y zf?h;`J865WotPWSz7rH{$QaDjKuPT5%H@@~u#VB2EAdubtBa;q@vG1y{*YXaLxJ$| zWP3Qu#@jGP3#^c0{6zw|W{8TY#T+K!H7Dr3awF{|s$sW)vLSm4p8c0b;K(~f z2hXqoAnehQOSeSM(pj_;yPVU{@(EN?#g|Lz0%@-HKdxUJGuJmXtqVct19^MH zR;(Qr6(v_aV}mO~SB6m-%K}u6`HArk_4}kFr;mTOoF}L7Q*sM`2$PpQ3-p2ehUt~C z9zo(lNVXXuQk(1iX@~^0v^J4?IeFN|RDVhJLWSC~jERdh4WXjgk zIjwSOEI5^AK;B2x6txC~|NQE5H;;Aj?RCejqLywy0lpj=i@z@q7~ zlAB$fty>qo2vb{`lhf9YDCu(=Q=&6jn<)0@nLe>Wn2KwJ?TqwPVxE zBcV*ihs6w+Dz9$d$C3uMZe9ll5xLJgRXbjPVc4$k_hAUs_o)eawI%tvTD8tXc@fIF zobM20E@F!a7mCdb-iPRx9yoIAO^PV=b*Rk=QwFLY(%+63wiYcXHV~|%o_$uG@7hLd zroy%<75Y&mW*G}aLSG&TBd=oFo5aorM`MT`c zzCCZX%2pkH^|M4V{ntj*ihq{g`De2dN(S zG!d`1VGXST_L@R^nvHLGt;0xH7zwVgF=XD(c&Z5$#DiBjE&{yx-ndIiF9RNpPpUA^ zsKZE=&uKT4Tc#BIeKzuW>-X{n1iS~D|{p448Np4W4i&D37ih+|Bn z3M7IG|6iDE6DCY@^&diY*V7cFize$#wsg)Hrk3@_Eq7v37o+6S5JatZUTGW66r+I_ zT(5n6FbKzd_-^9q8^w3UK79_?5|tdfWZ(w(N_6H|+yo3GI7oF7sJN5Vf0cQ{oRu=w=S~S zn_cfHqQOHrSqAIJ$k>W|u!`E_bX!~xfb7n}iq?SZgUMTFAb|Hs?h#xn!ByTG3DpUY ze5PZZ;n?8>FGmZrJRC9|*B|`?hW=ThFaKi)2c7c*9S~GYB_*nI4Tpo(*|XdNcU!Hf z{UV0B*tg_Kmv=|IYq66_p4Q@mWzc8b^!jVo#>d>eP-nx;u$P;tXD;Xb6e!_YoBv<% z$!Wn(M=Cg~MPWHm;q~grZXR`v%vvnbL)S|q#hA3PlQr|=T5{rcVJm7$o*$jg#kW#3 z?ZjRkSSdi$R=D9x3ABTl6vPFhi?_CdH&=Yvm5ji|Zo9?-x{1!nUG7OvjBnq=59m_LKz_fH_9c050OceFc01~Ob>*vTOtIpMK`zpJO?rX}&w-_>v1?v-V@TSNBX;qN`_S3pR+Xd));YY<0 zHp7V4KHm$#eY%((yWyhi)5D_X;olE{h?pIgUB^O!*k{sA5Hlg)brJ59$1C5LM0s}V zPzBOg7qQMx2Ls&6KS#zi;{lo#-a`*5Dqz^McN*3yOjC3owE2Yw`X44+ViMz0DR9a@ zFH)*Ie<26eM8;)E{UcAZ;>1Jq*PHSXFtTcR2MRjVVD6`8|dp@|4H>Z z9eg>sGr+mlbnvJ913aVbjF?bIzT$LHdt7(sU!m>-k6fu+p_!bZRuLymqAf~uh63Aac0vm*X zo#H~r3clLy#$!a6JRH1$Exk86e4$fEzJR0KRIz=~*vA%LgnM7Stm9S&{IzPxJHF_N z|L^w!>`xDN;-JSb?|*>(hcpZbKHJ2G&i_`!+tuo0pbWj(g;*&5;hVB`7XJ_r<_iO8a z-C^v5J;i`(3#@Eoq6@Ib0$Hf4nB<2GV#Si9(QSRz@I8GFDQl_$M=@e4j`xvh>uZbR zTR(mcWA=fq9njfP98rFJNCqh&&QHu3^J}cIKW0BpC+xRK60>wK^!%Q6lIi>x0@9Ej z8c%K{3G{n-tfcQscmzM&+Y_X^fS>II84`G1`v{qlZX&f8JRdslQOE3@Xfc3*m#ybO z9>4OReKj99JEvsaC*|-eDwOTtHXbw069VIoBfTl5vb3k*1>(L}idEzW5?I=c<~Z$0 zD_%zhc^MAr-7_R(rP&NHMJo>D zPcc{n3t0!5t&kY*e%{gcfkyg1w4L+I^|vR(mEk{r`r|hK&96iAgNuTtR__nD{_)4> z*H>54s^CO?{T|u?53rS4U^*3Teg0gIFnHMtJG4{b!DTZUepsB26jCiqD_EAueWT;q z8_4;s!SBEL4VPc0T6OLPvI#8J7XBBzufe_42HzvBFvPmn2!r99$*x{ug42(Y*>K_B zvY_Tw+%UnFF(z+6YX&wl+I?r#qi`nf>nPx9~r|y*YS<+s<%G|9BIrd*C9} z;z@5SGYjjg9uDQ}wQ!SXhx6Gv<6FoTTwiHV9W%0&CZf4=zkc@3E#<0;LO6L*>i$R# z^Vi2~>)$_HXXZfV!l6r4`IYveKDj}}Q-!CsB zecZd=t-poBXM8JGswuJ{;*EMJ(r|DeVB%kDqmEkzIVCPCXY`eW0F%_JVzu=&M#k_s2J&=9&^e$#POB`= z92SK!O)k64wVWU`tHSUfdkK zKr-`v{&&LgS^U8RkQYezg-&0T@sYoc__w2Ga4ypFP5%p#=jcoQebrd7{*De`t$B8S za4>yqZ^CPZ@W&#R&uQ;R#0fU-AH-1>3}$mTHTTotyT_YsRNLiUfgWnu zf(u5pYicf7l)x(&iy$_$7)AdA1Ki0CSD><_J>qRWY;+LB?q+E*U>qy{#u9oGr}~*R zS(DH~jjSNkAkD$}WWQ4F;SPbHK(e&Pt`~C$j#cuz>0M?S+@e; zMrznW1QdotCw(`oH2{x6SEdMGr|OD9qyrfNYHz!;^*V{Ro9Qt#B6LoMPqaR z@Yhp)N9Y$!mtmf(PgjBC(Scw>bq={Ty>a7t4dT|*=Qg5~^a%-RG+H2K?lO67gDdg& z00(rKjNZkKHX$<)Pd{D4`-9901w}LigEkM|Ve`;s5Ure!Woh*IQqG6(0BJ!`1EM znt70)8jiK$LL*xB#pwl?9KBu93te6Q({pISzX;p>UOf=2`-!>T>8e3xsHGf0O_p*O6SR3({wi+RQW#Ida>T=#m}k+%;wm^p}BrkrTe@?PL+5t;-4rn zP@&>rk0>em{^a%9Yz7}FZ#GZoc)b9Th|HV{xxB@Mz(|0E1drB^oiL#@${gRmbIERP z!;0Mm`sa-~0tdc41Kk;P+?Z*rNs(-hE8cR3Gx?7Eh}`UZdSGNwufgIz8k>;WA)W^y z+29>HoFVbCXhFo%31twBt~CQ!2x3E4Bi={+QI%=1st^6H%J=w$Ln+@Wcv({k50HHP zg)%NSrq#(gAO|m#o*v=Fh(T=Vg!_FYPKUQvci%n9?Iz^;ug_k0eOqn-xw|sGD|f8_YpX zrDUIz#m$!Yy4PMG(>YTb+Xpdc#aC5hUT6mjZrpGvT+E0yYVv>~X4mcDVtS2 zSnEQaL`0xp=M&=_!O)(c|DyW@w(_&k%=y;govBuLJ;eN^N9-8 zJX{06LU<84V2ex&(~VGJBk1};3z8;QNGo5cHdfepCdTW;nuSh*#Faa zc7Xqy9~bS_xi0X00Uy=9JKnWsBvk`zDQjYs}#@_aQ2mnPUByD{5Y)uO;w=4CP5*+)Q&b9r1~)iD zXzLm_C1JKoX_c|Bx$tk!o-zp?^a+>NVhgCnQ!YzGO$=tN)4}S1!p#Tc3ERWDYGh;U zzM2rg+0%0)SnjE+$YSw8caUEr^aEz*+YmWTqew==J5P`Y-puHC)5qyYkG z#Pl?1$4B(EB)m3knBW1sOo7Yntr|YjJ}J5&68t4yM+m=cUlskSv~W;)Rl7i&4q(Ia zF*b$xiW08wW7{Qm5zi_&RaB3)eHF*rSa29q3QN{-UAY0k>yD%mMo5rC!kwXlJ<3j) zn#GReH{hYiDcQz4w9D(6h$gfuNyu}8}oZ6Bn>Mi#h&vc)ma@nGfGbnEWb zVO4ila}PMY`vo3SrkrZwnjIaDZO~tTwx$6sPHp-Yx?nLP1e+OQnXTru2nimZJQbJX zK~KHnHtZmhx0QIh7?^dmwQU5%20Sn;H{tdWTEelVlS!J6-GghOt_sX?5!Z8O14Wzs zZ@z4%oh20T=~yNDxdREAPxKoHt7dgj7!d9e_2j4Km3YL{tv26Hx01JrF!cm{Rb6uJ zECWanXU%;Ls&CA~_TE@jwXFzU>DN%evnvbe0p~&qNkf%D21wcE93zrhlheT@f`vjT z+R=UGkOuB99R)q95vsq4GaN34)F*20yzSYSTp?GxBrgd zszh#^|F*K)6S@yj z$1o6`f=*zZvWtG>qXNqI_Kn*w0R%!sqR0F4>`_y)9hcW&Z*I+Sc!2v<2X;45DvY&g zd#Y~~r<3}Q@egAsO+384MWtYvG){5F36UL+215j<>?DI7n@dGbiQABeY8Z@jX#d@QGH<~&FC_(!s$qj&zcA*v5q<|BNPTABqlD9bDK^g+G|xX z_6(**2&%P5GfRBYka^P_O@p_U%<^cW3<)zW_x=Sc@F!f+4`exkl8nq+0SgJT)@s3m zg$EapUp_|k&dD?>8;)w7C7Lw6^vIU^_gkC5=y zKFM{NDSnb5--kE*>w=BBFeu4!_emfaS<* z(ypz#=T9x(x6O$@;MLc<0)N`-?j2};_Y5W3C++yAR~h#8xV#nnRAb{b^pXD<#xxPB z+Tb39%Bk7L_#QY^2zbDaA~wh0@w?BMY`67XNEWK87_c>+q6u6+2xHws9fz}LkeU;u9SD7T+ttr=m zc-am7?9mLWZUGEf2Y`bTa^M=5>=rxkuJKd@=;|yiCgW*U(5KK-n5fm%8Uj6F{BGB} znliOjX($Og@EA`IdxD!K;SQgWUpHSawD5??kb$aa@QQOL&o&=!Y+^2z(il=n@$Cvg zWW2s|n+l1bRz`TmLm@Vf^nxJ|j&{$uv0p`*`RM%E>>n=@SCA#dr#zS8AN8?~@Kls% zmqRKh4BdAi5!-2{qtS4ZU^@ijp8|q&2tCBpA^rVFt(WngF2UF}L{(=AwwBmiul&>7 z+Sj_N*ITih5N0PPu%Ju_a%z$+{&#MB1h1n6Mqz3r?!B{S*w}ah6u@-Rh5!}l%nhm0 z`s9(Kfh#@$SA0^DPHc*!GZgJstjY#g%K4;2rR_+k7JPXG6(YCmo`UzRk@`T}I{vnb zX=Ha6L7DsphPt`9UW7uj*QCU*{aMPUb5lm^d}ww!HrnGj*8XtIp{qg0T1{*|TyeU% zs^+5wNtlZ^HuIka6-JI;y6|iNg0N{KnyX6B3|ib5dMz?ag_`D&nv{owM~?E43LdSx zM5x$UDTRiY$8wVg_l3VnO!dQE2o&mRbg2Q)*IYPp!s5vb0Gv-e%i`1uR&|Kl3^BtmgQkJ2r%~Fw2WhS?_E#c zB7)%F;A=#POvbjYf*R*jv$zb@es!N|_p?PH=&7YnB#ruhsH9iD#XOr@fV`kMCtsk) zJG*;7#tb;Qk3{3Ze=jnadg3v$wttGcBe}Rflddv3=^bau=$icmL8IImxvfx@!@@$D zHNy(7vpu^5d4?B6ix{wXLvGm396h!`>;k4*{H*);4I+y*N>%pC2S*YAL`elVcG~me zjEw16+KGxX1^CzqW1s$GRiPTs8n2UYstWx*bZdDx5Jis@A6Rc5VTvvhyn6vrR9keP8kOLxU4sl-*$7-DJd}FZ1@7)o*HI@w9tyYcA zvs#=YZ)z3Az`_1n`U3g~JsZ5Jh`3d4_>9`V-jl*1Db@+jswoRwT~L^)rrJN0MXLcU zFm5vvgNCF}P(OvK@)S_y$fP zW+^ton=8fw-XNzetC!MOA^>`(dx<9-)U9v#S z9>A&uZ{jlI^c1&Az8wF_BFc1!OL>$K3f;qU z-^_h#>1T0l&-ZG01SsDg$<6cGGj18Vv7L;@hrFC)f8+Jx!~7v18Gcdz9B9p@XDB|r z<6%qRcqS_g=p+0#rgPp?3vQa=mfgpC1tRSNvJ_0|2~o3WDC15!&yKk3oQ$dxWMTPO z|A6a-?PBh4U)|X~93SJ_;)^nl8-TvVX@KSvvz(E!bal2|~ z;CWO_Jl)>j-gQv6cW+NeyiOMR!MigGVo=>7>g*lE7{^FDIeF_B%`Dk;!^~E9g0ztP zWuh(RawZdo<55*RNtt`k*fF>7)s`)}vuGY{B_j~ln3OZ@d@_XTqk6Bx$?Osp?oxf3 z0k!TFfmid!jf4}yQyd189er<2xvw(;&oP&%?VO7mM=Rl$9hBzLIa$qS(W+UMBNWH3 z2CUZW+l6CjDEtrp&vv3ae?Mn%ckRVsFfH6uLzMWm3729w4-YK_RN=D#jjgphS=~l* z7aL>nW;zG?In&Jd^SWZh*R2>vT#Yr2AkzrKY zkuBAS*TB5{x?EBl+%om#j8zRzk11eiAmFyc22)*NQ>Qfw&TbnCmrd(&N6<(g>NrV1eaUl3bv1cuc@rdD<-ULoGcp;KGFZnIC~nFY zOa3|;!>Q3%Vh%dD5Z8)@C{6J_%CU{Q~|%jMroVs*8NgX zd2A&&^XUXhp&^@cwCy5nSbvy*sySfP?qLlX_b_xcQm80$-g#ymDy6C#A%a&s*wl@_ zXe-V)n)S4MutF2E)7h^UIwQb1A?)eX_`uvmtQE0r0LVE7bU(!_oghmb$HD%7sZ=S` z1BFAQ#x3kn&fFIYejw2LY6v2Sz-%w=vDE`!@xQpWAAQZuu_d1bXL`lja(-8^5byoC zrT>j1n_Gjs$ZYi9MB7SEW+%m3auA%5Idz?KvrH4WvFXGP)Z}LV_CFABV^M}JPWo*n zpGE}nwYE|<78%$_E%p+p8+hQM+R6y;eZ|~xyO^^dmD%O~sct96?rTObgLmGlQ)4QS z35kJ_zJ`ym>ap56sY4X0dtv_0a}%5bmBAE8`Weh>eL4$U9gD&OKXo@$SaaqRlQ13+ z`-F)rJ9j~76j;zGrNa{7t~ohpwa19ve~SY4kmo`xkN`F13`#BJ&g2G#eOlm7w6koJ zSuxPWKHDmHZVEOHYPF<%Dj56Wc~HUQ=RO3x0Vt-ZnHWS>Rc6}Mlq^nT0jyHBfy*i3 zb7t4~gepHTP^&gNiCBQM#908-(+pEF@==H5r$mgx4;-C7j6jcYacrvie+rT<)F*kT z^D#q9F^9%YB~6z0E~>Ph`>LNyd`8^ct!ve%>}=VQsP+AvEM)$(NF{`9Ys?M)g1~Oh zHjsMu?TO{)LEagHR~PIs0_jBG%G?`*7pyZ#?cK~iO=+oHTcODKZOFCFY-(}(Z^gp2u8%{VUPmA)CQgVQ%tpqI*< zq&~(L2Js_=5dmluJTzjxZF2jJjR?~q(WHQB!81kgf1sDLc~fv<7FT?`9)woNv*e(%uI-Be&|Ddq zFb~5A&Wn7e1Gh)dS04-? z+{6Fz=RHl}&5c$6JskQUEFAr`g~iwY4OgG9Vw(83y87TJ{`XQBK3QT|#|?>S(leC;UbHXt$Z@Ph!#Cx@dNAfCMX6Vr#sh@s;p~ zb_*lV7)=BKdukC2W?;qpLF$t5XqmYp_4fGXF>hRr{q@rTXO3V31d6-ja<{53UeT9I zr0}1x3_!e90iVfRj}fWK7z4dmGPtS+&LGGXcS`g`Ou zGX(yoE_w-_apHabwk|+Aqv^p^JV2~}QJ29uN9MaZ&yQL5JC+&jP_Iv6RZ2eG(`p#N zRGG2@JB5@O%$Y_Q5me#J%XI>#A}44XH_opegh4>`>Km41Dd^xXGOm#6+*bXLsy+bG z4g&@G(J-wtd)f^*w3TYVT{pfr&d)WV+tM~+7ql$GWVrn7Ic=S;AXXp(CqO+Y_JJJTGwN3Br^{}Bc1P}hShG2a*X%bGM1>iUQ=N%YRVKctfv&=#4g8V%@m-T_9_tTxNh-9 z#_FVZB+|>uKrPE0ea zin$ubutQ%pBa-a?>cSG~R(0^9d(kkWpQ7y<^`Pzqas5Z8T4eAx zwH6!p<(OzE1XQ4l1=#JrQJoiD!@kpGoVGrPtg2PC_#|LT-G1;ZTwJd1M(b`e0Kh+Q z{qYOR*gO3V2Kwn5JU*6_227d(JsLcNx$puXCxWe-{mk(yk+5N_?#B@IKZPaROpbY_2&a2yHpcFRd}LyXeUPt=lK5bF zF;t!H)M^*rMZm9CQs)jRjy2n263x|0YyF>U&u3dK*;%&b!Yab;oNP|-FVvQ=CO!QE zPAXgGP~wRTZ&+K8_F1A7GO`0RmUPg*FT-B+*WkuD`KEG_4g!1#c7LSoJy|z=Pf`Hu1GmU6nHl!D5wyO*+bx?>gXKPmxon-{E)x zvJHGy01Sz(?9NQGnjA(7(_1wuie;-_svf$AZ6cg{h$wokpngl`vZdC#01+0ZRdUT* z^-D(ark$MwI~E&JBK(|!A?fc;_pw-pJP^u=+%P@D-RgEv8uC`Zbm*2!r@syYcs38m z0N}Oe{9j*o<3nrjtAan+RW~Xb7B}IKQI0^Qm{kr8I3%{OCY#%>5%4#*Y}L+m7TI+fWq#h&K_BG~tEVFt zF*rNil1lWSkW(npe?p1YbH$e?;)0#zIe{w-L(bMepVP!FXfs*y{AARn7Ss|40SoB4 znBH7%mNTVXdrf(zm+8i$U2q{I1XwiF8&>Ebtcc?fD8sJp4s@zL=xv-(2MDDF)e;6I#@q3L1~!6wG|4qG-6BB zpc%If?G(#ZVb=HcmW{}a_^zU~Dz!bso&&ZDp4o-LZ5~>zlJ0q1Ze$lPn-3EHHw@I| zj5jaLGjrrE+KgD{ibXx#8o^U|{~uTGU3-rwlwn{$|49cI_+wRP7jQXlU%N}x^v#6c z4%?&C+A~KBa&rm(sOwl`hk&|R|Qvyq10X+o^~v@y~gu4O!wg5!0#GUUjZ!dKk@{*;#_5kzHVIKch< zguDmPK%#8g7WM9T{uI>Po+8f4%#qg+0DFhO$#H%>d8r5qTuPYzIDUo0WEw2CHYitr zM@-5-MGR^wcHnNXhim+WB%C1PWZ(+2{(x0ug`+05Ho1)DN?L_4T9w}Ih+)7|mAnUz z{GYkcrs%^eK9hPoGUm4a}w(;?C3uLkb)2`mc`X1JX zu-FJ3NYU`Y;ic)OR2aeVuF)zgTG#z_wCG6cYQP>qNNbpy0##4W&w8loTFi{Bk7|ye zM@<_mFk9=Dg4f2=Bl80%=(eo5Q;#z&^}BTG@He(sJoqm!wVStQ{A1;(;o5B2=Ew2C zM(e>Tptsh3OjA^6+Huk_bH`#%Ys*o<>v63#_Fa;(aKLGUFVeE;;-O?8d&Z3t)uK+mo&?_AMAJ`W3Od(|9tf!}UOF9-IGPG2*3Pef}& zW}F}aRki=D@tyIQ%Yd&}MolerP|i&5mmZ%%jDrcqKn^OBW%~0|)N*;I*6i&*vV#}% z3Le0%Bc)vWO>km_p21i2o?=uW2&)g`T#t>rNanYw9mj{%&kNnOy#)RiySr3p1tJ$C zf{`rZT}VRO6`m}S<_P$)VWyC;Qh~>Q7TcMkHveII_UfBB^+OjL)eqG1zKkCS`bxQ~ zeRqC!#-Z>XE738f3bKvU&*jUx&j)xK41gfC#Zq6SzTcGqMLkK7;uy z21PMo$z~Hpw}oJPtW7S>D~7aWX(Ri6TpGi?Tk1qIU<-FZJYo-l{5G$Q3K#jLml*lM z{c9-$&TSMhjMf2xvV6@rvt{c-?-m7keFBej3Wdh9M339|xf{Sn^2pxNGnqkWSefTj zJi|S}-uZlPYcIap#;Dm)B>#B)gp3?_Mo5=eQscac=zu;%+HPz3z}}q=HYb99y0+?* zHnq5Df7KS9&YeZF1^cbvK>MB<*$$`wWx@0>vG?=nJzJ6ZDhjuVh6Px99Y+agX=iE= z@fPCI2{z+qt@~q|%sCDkF!auYn7DeAKc~oqtav>F4V+wo$^Q8A9Mc2OpkS?-?zXBhNMOp(-7MPRcr_?(r=0MzYljB||V!JuxhF_+IRyl^yz&SlOIXaX7%MsS`@BDBvQ?ztZsbfQjx4uIV^QohI5zWLqay!pVE)t&2cltnXJkI%8}Uzvc$ovTX-_9O>fVOd{(nVk2`y$?W>ts^H2P&1?iUSPmgvJ>#GsU>0^#bxW2m zldd~O3vrWtk<67IvcVorvGie;6aZ4$FdcALhx;2K41aE4y@&tDAG$<7pO0T6QAHT} zU`8U$C&O&AvJWK&h2}{sqvD1-AD{T$CjK%qVHJ1^)bRyWkFg|T) zEdHd1Q8#ZL0t0?Y2g~>V9uk)Lz*zZdW8)cAIOo&2CSa|@>*m1Hj2mf-(+dZVhwWXZ zSRDu+cC{86aJ>!+AjVl*9Ax^1*V6FD_;7j?H&qbY8~iyK9NxO+`xfkt^KbF3xHOsf zy|HriZ#PwhrcwZ0*>@t%K0D^%4Gq>T5|Dh~62SOA22wxHNBTQx!Tv=KufZ$P`cu68 z5T_ST;9z5Lq3UBnsB(+4yDZ@kq2tq42kpAkGciv@zVfC3&Zn+&JpPx`7x~X<0s7;0 z+#KO{=efPCgf}#TI^Lxr5=Y;5SJLJ{rKu1Vd0$p+!7L%8+gDZ1yVi>!*+QU@0|{3s zuV=E|415SE5doWk>J57Jn42%0p4+n_0nheT8+9<{S0_0LV7E+bfM~?l2n#oBU78UM^TSiL)q-apQ*j3WOg6Fao$lS) z#VHa}{+F!Kq8@R1&+=eMR|4aam{ch}kmFhBI7|vg62y z^V5WVR$6P3q{mEy4eF>3F2BQ0ZBe{4JZ{|ADgxr?siy6kLS0cgB+IwA*W6&OaI}Z8C2--@quo1v7^^hoD1?w z0PF;6C$bK=`5c0&4HVHts(Vk|pk_a=6(CXAox-RXe*5Ra6+9; z&hSAvcwyj*{R{@+C;Jk~MR3e>G^sMZ>N~_SY%kpyMuvWiw6Vk_lqkM?Q#L=O@}=Hd z`ko{hYzSS9{(|{e05-k3aser1F%~Z2>rFo}VUQDqhFFk9#CF0A@14!=Q+>bZSM1f7 zjLa(7GO@HBWRakP+WZb3a*nX?w43GN0?|RoRDGQ$=a2zmUy5(AveeXf%Bdtl@2fYNT?k;vM&x+SX~PGqdFNZ9~G7 z%NvnoOPoqwd-JOh040;^*L7sT^kEs2qk?r@*{U&CF;n@4%-DV@a8}?nCIs6Vp=4EZ zae)IZedM%4S*7spBIT}d))*IW@OX}W?4*-wEG+hXRV7%VuQd%QbtcSIT*4`4*JPV3 zK52iHv5=|x-u4HXEAKU6HM`t%SQhR0utat*XxeT}#`e{3&be*j0!46gTcsddc%Nrr ziB@+&GpZ`SLj_7m*-|pgFSy48d{(7!QzX(&ZL`|o0~&V;#}7cIu$eoT1(PdWj2x$H zX&H9Swu5yBtk$)5?n*1%#Kzjd>^2uMKYcmncse0o<}4z6%7Rp|R*wjybux`p?FxJ3 zyBQWYeiM7PidyC^(V*DoNMYCkQ3w0{nY6)@6+CUe;L<%XRXvMbL?}0>0>4X}G=86Q z7)P#4ui_c^BGw>iSUl^^*xXCZUcj~EvspUJO z#Cy&js*Zdp9~|bF!$nYH05V$CBZd+#tUl<Ve#GLHc3oCsbO=Yd% zEo6JPt{O+`XZ+?VWulDa)wlYaBZJW0=iG`yO;GqOZH1hm1+jV;x75@@U^|tna-0OMz!1$QpfcN(;vApJI$BK1n0l= zeH@NPNr+LI#|DF{EBy_Ct6A}r_>EGdav+cYEg8Ga`BkOVQnmZA3VtPq%PyoVleX^- zpOvKBQG(BnG%!D=f6zQHlZmHjW6rWz2}+458y?3fLafkLoxZf17lEx5PBq)0oecZX zOng@*#*Sthif#wu6IzNwS(Kw)Rg7O*O7&Ap{TE7!ngl#{E%APHvEF)NGrL8GHV7%J zHht%&0-X*yfb@=G1k~{r3MRkl2~FK;5L|DYR|Lxm$H*9#pZUF^(-|iWSAKx7;W>f zKk24jDgGecS#QiKS8ZmrT(M3u7ywte`%Xnoe{?M7ziP$~)sOKM)cW_BCHKp2I~Uv0 zki@!+FEg4E86(nu%xi*l!BkC;dfo($c42XPw)1F3y11DVfcrXZ8e-OYI*uTAD`F>F zc9PDgtXHksMgnLdAFF1m7*8fr-*|cEgE`Rq-_y9EzY{ASkm-P{gsxDQP7TYvf>(Eh z=06Q?-R<oZcVIw)wjA9u*yRID;h>`zPMtw)AWi;^{z@)={PW8dUIKx`ME;42F>PKoqBy{P3>#MUV zhS-(mR0xZ2&2rKtWX>XYYw;=6T}m=p2&;p)fHl?~M0qS1l^fgriwj&xAQ4x>E~W^0 zVL)iYVj*8~SlPL$9JR2cDBZ=Ho~+l;)Q0=u7;m2lF+R{zx4<7-dC5RwB5(?9Kmk<~ z>5ht{WJaPSM)S8U4Q94<>ov>Me2tD>^cQ-ShK%~;pNBf^$1#$g3Z9E2*5(p?2oTeI-Wb=Gi^N9U(S-!+mS|{ ze6(z9!ZHrq9I5i7h}mvY_?Z+lg1K(wMDpA#6{vnb$QmNrl8O!oZz^;LlAi`yqrm)ZlKv}$4%@s6hWh>m zRCb}Z+X$bgs26Pmo!VSz7&t~n7dxU!?L$6Q2kGdkn93Uz1E{uGz14E&^45LKRgL1)8%pA4bT_F`~yfTsA7BowH1X%ZqK+fZs5I z4$YCm9vsOIfomB-=Z8572*cXWb$KbMYX~Bdc;zUm;-E^IX$EDr!|AN{N3jF+s`koH&b8V2af5_d4v26Y$~igy z0BLnkVarf>1G^B?~38$>K9%=x+>(^*&)Cpmb@H`Qt&P! zH@fG-8G`vWdhy*7?RLLucKi&_xzHcjAF*8dc##D6{N&jlBB~Gb=@eKDL@~Jo4`~1X zxBBbR6yDug1&+h)=w}XfKRW@rxWFeFo_sZ=#Ek*?K-Cuw9cg)v*=|`H655}j{ z!Ksd#-M#y2q6+EGU@WHbQFWP6K`LZpTxw~FqRlj&v<}|H5u9B>8u3bOUYPmzLlG>7~fWs zKz`euyh1P@7zNrusx;3}aNi3&^|hA^T=g6+miNnQpSCTJt&jOTVgx((4WfWPi2QAU z!i_;Z7NP**s1?U*!lsnXn=$T!o+ID#Aq4UkM3YzA@Uqf$j?D9D3@O32Q1uIox?q~P z8(rfe(Iy_%tRlK{;-5+sEV34H*~ zLAxRr5?@N{P7|!KV>y-7de*?zdEIP;I5{jDjYp~KYN2X{h`Ow50-hHdHfM>5VN(^y zH7-gfngVkbn1JH0x}W4@53FDl_%yb%cFtVBWk9d_NW`$(8Vgg_AWc~J%f2^E_ROoE z*5a(dgXncpwii`OYHo50^oMg3HH%bWN?)y80*P8G!mXaLzP%R;^8{Ce{^N;~pG#YC zlF+fP5Lx=4R_Y9+!2o-!kQTW6UxL}!&PC9Ls-7{|4<~$8C^!kXoepv9&N8{%a!i!% z&-T`7uHe7ttUiiAyt$_26|s$AD2AHw709pYCV}Ly9Zu1brLN#ve*&Mas!t9ttn2e~ z>;w1K5Qf;n87wOd#(v_b!9OxvQpE7;XOQ_)+kSavonkLgWjg;mOzr)G9ym!|6dk1L z{QL8xT`Y7c8NJm5Zq286VTXhUE$5gQ^jap`bcX)nh2}ueR~3V`><8v+T4A}gR`1$Y z6rc;lFeE8^FY3gc7qyYP>YrPK+n8U z19Em1DxJem>P)Qc&3G9-HcmQPIYPe`t*!hXH#?T4^Ozb0k zEdo@~1|5AZbx`$NF zPDe~L@DRI02AmL0WHej3hUa(#n{R#KJbLBf@&4%yM>(JI`7@p$-MY&yVqcZtjP7I| zo^M-kbHLaC6pHfc9C{qJ|sa_F&`R__ER_(zU~fJU*F1QylPe zGp>puHkJFvBfWdFhhPEjZfKIAcyBsK@Uz_tM`P|!8#4N+$OVZmj(8=Dpe=qK9naoy zQV)8{`2F4hkB{5KyX1qNu!xSs7^?Qa-~@b4W5f|e=s3!76~-R+x|99k=L-uRO&T|` zy6rjSg3hk1qugob(BT6ZveoiQlfm%(6n2Ymb-m%D8R&)wXoQRKqmfy}y2w&`;>)<) zk^^|$^QG6#Xr}AxL(=dH`yz-ocYgJp?NnYKMsCuR`3xp!Nd_BP$MK6|a&X527 zd;*Wx5UcAsZoeHIBWP^5(u43+Fq$q~`0F8|pGgXPeFRSjst@=7r7}Ta+irR-x(H`; zwet6ds#b6@95-dPi=?TCy%B(PFsf$>Nx9rk;ZIxA-jg==Z&@=45-aFGwy3M79!r&w z^>8qAvuwJ#+0SW78pd<=M(i_lr=-9S#o->8un%35nzyWSX9>&>NbN^VqL> zQhralte6%T_cQ~?&Y>T`-E=v@#WM;>sswuN|!9T(~dgiLdv%r8N?s-~Q z)&a3`G{NJ1aIGA{!Lc{SQr&j-2FbFhfL@Jpvy&I}sz_;b(eUFGuZ(DA;w=}u&W-bA z^f+;Z3Ly@)y@o?xAtSqG4DigP4P32oA;Q-YQN)!wZ^~6z*0FWan_}yPW#@c70291% zBdN--Bza&Di7K$*RhCQu_|4>?8N?u+&exxPH`_lyoIsCS&;cuUYSIwMLhxGkYlP|W zhHM3-%L^gnKTw`)Of~|5PWuDgm#5*ta6m+F8)tx8`;t%PEDOT1BO)$F1`v+q_yVvy z$gbN~;p6+L*%sZ?L-!+y9njn0p_!EgxV&?%3qW-6R}eJyomiPxf^%@=)}{8#`qft} zwyO}SCheoEA^wmWE8rXHx!nRF3zQ$vXK|w?dS`=z0R>`K)J8fj_;57q+@J6O>D4zDF% znX#q|!#c)o;AUDMLwkfCaq!A0F<5|7AQ?Ox3`N6>gsLaqleQ;Xv+B^3t=P8;9HI&X zbnsNE9u$7Wr5fW{y^DbCTQJ!gf=#qSjh~I*Qi!3HvC;Xw#XcF18q@@(h);uQ6AM*? zhIGm1&r3}LhDB7pcpe?iR3S9~^gk*w6I(*_OCsj_)c-|u%d!AbtCy~bDciI z-gRzyEII|U2CM_64d9GYwFvkOVU_E+Dha^=WdMqD6F8!laBT56ffvu52_Bp$24o` zxZwYwf2_mMrf;$ny0cEtc;<(iNZIsCSEsmFQwL5)6**+13XxoW;6e$`mfRaGwb>fH zm}i`+!`NVaisuiQv^jzZ@IkKhe7xQm(BF4uq`|FQa96P1mf{Y$AZH{0B!W|8QIrio zlw$|QCEoD{yP}v}0qn6eDYJx-O&+=KRIcZX6WuJ!8m2J`m zqkoz&jJ2$Py=bm{1DmsYkmma^JQ+9^J6^+Te2B-)`S-(JsFa*E<%3Y@DhK}%&Hq34 z-n}`lWXTWvDhIqXLW3k4069<06C}YI-WfhjVCL>!fER244X}qmH-v8RF#sL1td-Ug zD~JEG!&cZK*|PPQ6n0n<*4q1VcJ@kttv`Z(zkF5I>C<=&=g#bvID41qb52!OR#sMK zR#sM)tzgLdXh12cQ2?SfGuZOYcvgw4Zta9?hT5KMKV9%ywH!2;pbB{8A4Y5=Oz*vwMUzpyJH0)C%1iea#PF z$op1?hUeb{oZY>_CZatp6zU0XYBC5y7NNpnTfctEkG5o~W1v*2vif2NZ;ieYi7!=K zM!Kx^ULU<+B1&X4#hK`$3qcT!LVaE4gS>C3EweVy=O*-Oj!x^9jl8TXsW63p!&bC~ zl~BqTAS6g8nGhp{Oi!*B5r=PB04?@klW+u=xTI&ywpk`eHLka6d z=FCfyQ3_E(`v!=9=D#{G(YVb8zB8kaq$;3kNFY3Ax{#D~q0{I?UdY|PUP{ey@%a|O zfSiNVaNJX1=4E;Esc1iMyg2;l3WhyO#N_1~I8~|s3qKCYd|j`E!XDF}Lp9Nr5y(c; zJD~VvJsk~v+pRXFF(kHOh1+Cu!UyS(^Y)_>ceBQ8q@txU9{o0jk2PIKvX9dBjMXi# zA%Kk|3IpNUN3lP^irjvwHDy{0I6BIWjyt7R`0UhJ0quz9q3y5v_L@)He98pHC~*CI7hCB&PCK#XhjLy3#Gv1tISwiX(c=&{K&ibAsneCakLnaobN+nuE|VQrm)#S#p{x@DK~_4F`dR*^8Hpz&#| zhRXHkRBKQ8lIbH9_57@sZ5MYVHl zzr){0S1fa!R;-I^1Cv@-xyi!7V88Peaq(32FzOGv=}Y5YoL&?`agh?KESO;D_i$;{ z!ZqA-Twl`CX~U@@Y-jO7dMd4I96-ghI%8c2p# zoOoC#@zPHl$&S|qZp;?2Rk4CqBn?>J>tS9DXTa2u5^X5JaFmEc^9AXLY~$HsJg0y& z+Ba$GiWok5@Qjg-?OKttO$CxSIyPp3jxlgzFdGUEm(P+I9cLEzK5sG{P`W8yi=ako zF)J%PW1A`tPc~L`vq!{&$)ZWpAu}SCy+RBLlfmyQf6a^xhHIo(s#=VaGy#IeaQL)q z4v;d?Bw|9&tB5CCwon;Xhg~GMZ^?;F09J~?5{PzCh$fvmKhJ%Q> z0{}r@;MHAjJz-s}_t&5aZl<=_5&1up)#s3kq6H%ue_oH{Bs$0Apn_ zjb!Fkn+VE4lm>P!j&Of0tLbnEJPelvP0B#XR4{E{A%_7XFw~hNg4?g%8q#rCh%OS! zcWg1JSPm9MLSJ$+72c5OHH5mv3~(G1EWE{`<^Y$CoGX9tON?5$GLocT9b}un!S{u) zfa9%*P2?38$WO4xR1w<6Hj>$1AuP@CVC@j0_QP-{hh`HAq9&h`h!~RSg^dl6HqByz zUzCd&2b8-nXXgA)xU3qy@zms@4yo19?h-+R>=sC#IXU^aNANEzx?yvjs@KS5ZkO-~6^abzdD3kI}0QW(ua-r%A(CxFU{Kv-lFTrqh%*dDB)f#{fvZYMHc^Ih=W=GGZ70UCJD2a3;NsWJImn z`7YV#OFklw9ThAmHLJ#XQPH}xUV{J9`eU%AoVv|e$`4loW7AjG9mxV@u3X-mQO9K1 z?HuB+?ePx?lXzk)gPMto4@ML8@q89)RwcA9(H04}w}}YY=%0Z;!yu(LhV>6S3Bj|F z;bH?pS_&)>9_Qz9YZmM*Wdc$-zJkh9@3s}s48g#nv`&OY5xXF}$18j2jTxJh4S>|+ zQ}usV>?cwGP4Md4Ka~NukUk(J=QbB|xcj`rl~p?Tghe#Y-QrmS6ASS$LK4QdZSO&E(X-;#FsqRE^{;-ai z89;5%+(9C+RJqE$(9iiI1BLXvyZqXJw^lHdRwQoYK5${nlcK(qkfWk$U>%+S0^GulIEy@-@PrIr=tczs zS!Q*m0vJ=QPNFaf1lG}5yLc`1VHw~g7dNtOtXZaU0hN@n?ph%@0+DwHRtl|?v@nvY zw)-#8n5JQD`wP_h<`9`gIUqIx&y6EG(TpDci=Zu|SzqVzR}-D(bq>-fCx+lx2*}*qD$PG`+7N3JD|Yk}$I}U2y?~tk#di z$)|EdUktl)QMt4U|0MQZZS{xloNHlOuU0HBLsT2kb1W%k#eircEGik?F66Y3GH3SL z1t&763dc0_$HMhnL+P~DU%lv0u>zb3v$hJXl|!G{o!Z-Ml_ttA(?at6+9s3G`@-&5 zv-*9U^2Zd9WN&rYC{;W*R1A678L`PERJ;X;veJxQ;X^${)tas>Jlxk~^lRggnjk@pTWMPf-@ZC?)&ug*AL)1H$e2Z3qXI@r31YO&lf0YJ;1zM_yhRAQ&l(yTb`@on zyNo9@PFe>zh1V zhiDLcC9Yoat<6J|#7oT}N$i9V>5|Z0dt7Ln#)9gdeDjwu#GnBsU4ym<|eEk6Eh2@cv$4_9@Xz;Nh z7T#OjBp@{yL$kd)fx6G7PwGDW4dJQ`1dMaoX_)-bm09gkx(M!nK*ig{ow8m=ltD(W9sk5#iNRwHn0y2jM*3(vZ zI7I%8XYG6UZ!K>u-}_c0NbzMGd*8?snPNzZa+!l0m$v&&YaA3yZzSWBaF8LzKPr64 zzhSg3ZL#?Q;xup#qRTB21V{nP^%zbQB5~#B9zb)Aio<0JB}7AJZpoYippYN>LYBsU zGpvb539j3HAVUn2eDxq%!<7pQrw z&bHWe$=TT9cuP$*VBkm&UY=W&evrASAZdQ|oT-OhRhQ>tGI4O&WIg8TTzo>=VeFx^ zP+HjA(?C0>RI%tmX3-dF#2eqX5wRa96b6!grFslpnIN_mot$}$>>Je;g}i=A#j)OS z%+R32frCT@5AI51ITx8iM9{$EB=O6?K#A>l5Hmyqb@nvf07=$E?BMqn1s(E^_1uKf z;bJ3TZ2s{!Kzx)lfkkrqV46W>k5+)Ny?~F$V5g8&(WI3tcL@CDxY6M$@ogPEsih>i zq9I}}+embW`6g4&RL--M2aZ6w@08-oOxAg^V%?%+nP4<^A_7jwFq-^D;i>?#;qmr0 z6H2yDKBT1=U02>`RCQB=h@1f+32|I(L#l%|^4I$6mLd_DEUlD*myzNzCvEmNlZVgE|8eJ zMv~m5gr$kJ^t*jEqv;_C^8P#V=lS^k}^wW=3XD8d35Q@K<6}+T~5TNeP{RBUW)zh9ly94lr@R^=k{R zwp|+ogv}dWxQjD|!{WjzZ$cCg8Zq_9;bWgv+Z8N82x0jL*nJjgZxJv18OY0Dy6El4Hfp<^8*C){F?(7G)6 zV84*;Xs_6mZadfu7GOLsUqGJ|1jU{5Q-+iFB zKKHuAR`ScFd4Vhgo>(p|-v}=Y^vg{Z_-L^*7Tv9KijQ_;$)cZa;6r}8+*EG|59mrA z@k8QD2v|BoDiuW7h{84*h@ypth+;$b<{nOsOiVDESW-7>bDqqc3*>TcRiS;p)k9d~ zW8tQpY^ypi!^P%51vTrD%n>-`#y4eSn-ewJ23V|=L$-KA+x81^la%7wQLN4Jb^3aH zzI{zIa*}t#(Zc1JZF`}fF->|=TU`OVAb?0O=G!u7K^lL2zjXD|H1}1p>(tY`Y1DUj zllMdL(k9Es*_v+8={wogWOB#Lm`0bYrRuT1UmZN{_8-e3D4a2quzlzuoJYmxEjDMl zd&@950f>W1e2o@(F*Lf2^$|)9a5sfKw+ULnf4+q%Lkh#o)#q~QW_5hq4pd?h^rE|U z1jkpkiW6(`;2bAF<}wD(@N9W$BcV)CP2S>PCLOvRJz;K8`kq!%K@Gp@s5E}(9d0-g z?var&m$-@}%t@v(m9H|nF$ehqR3~`*oYpn=dD(j1GQ}05!=A04jGb5j+PuzYMPS6S zLIJiaUmgF{m<~^CAFdqSK^AQYp;#L_rItn;;#nzdV~R-?>u)JoH4kwRtu`!fD7A^p5OP zPD`fuNrw|Y^5=E)^X2`z=dH;4lrXut0A+3h#7Jm)xD~G2!3StZ>w0On=-=% zg&-5b%d3bQdy2doca}d8vjgMBk?p^v98DS(0lj13rZStR6G2h>EB$j$2vDK!!@@>i3b-0B5n<9muNceRhwNoamcyzBxE}dDvsN z!fW&M@66gALe*{D=(-69L%UkSncRmgFsvTpexbu>>K`-N3xV^jhf}0?gc?zM({VnhUagMK|Sy5 zd@7oJpIOf~yGUhW=~{_mK#o_&(H!sHuna|rz@5TF?XV3I3XYR z1~6DCE15PN=SKIAz_XnS_niQs7u8z>Rbn#h20N!W-eIVK{!k*-u!#*WQIm$7A>byv zdP~6Br{ecs;=N86aLYjl zccGzn$;LK3Iu_oI#ORX!S_9`)@5ts%q8PlnxJMe-NI!r6yv^k7PluRx-8OHM{%$yD z8;9>GlzFrgw3g4~YOIc|fPy;}$&ZTls;Q;$(qheUvpzXq8B|;s#w!e!( z!02{{PvNzyzUw^e;Os;1VDvfHC)^P=VTo*>m@Sy=#2C$BgW_eEt51ww2ct;l-Gabn z&(<&LDQ2v+%{rIo^-D3TA~dNJH*j15h-)@d-;tHX@;7L!U`?PF`9=?NZG)#t5V43~ z!ddvMw|e8p7OahZ-ByK2S=t(bk04lrL|i+g4_KJ=j7K<#0ek~Pzqet`0W~5hJOE;- zx9>O%hHP591hQ@5aM2OpV8D2vpI2MLQ7UBe0}7bi)&eTM_l_61)qREqoqy^b@Txt4 z=^b>C@@1nh@>$9Xh4$rwKY4Z@Nn~?%N`aeb8Rmn^D%1@NGZlj7=LVzz7CF4Cm#HIZ zj$GY_3(|LAR=-}sB6RZ*tR-?vS2PGm)u?jZa=ka|&2IO0dmeJ?6HFN$WV+9F4eoV= zHGx$SSdAAX%6tb8fzNyUICI47qog2F#Q=UtR|@PivIav;MHW#=eXGmFxj$+D7N_95 zd)u=6I|qi6dIDqa!}bUB2pt^2kN5y%FdEEVYhPEaEO0! za%Zdi9BTz!H`-81utm-G73)^}q&+hZdkGngy0|0aE8Jf%Us1&y|4f@-J%oMHA4!6> zz^r}w@Y!MsZVq-|cMG>sO7w;HZZM=GX7BEHwkjAUe}W$U2CfNAK>YfeTs~7)B(=e> zWL#EUUq?0#xiRvj_h79vc(h$BFQq&5C|lVHg={9V+>%bJxn2!pn;$H4`^M5e>GAU` zAB~sOdBbvgMP{vpF-)lsAuvYW4kX>)U>7R%Xm4AkH&R>OqOX$h?{(^&Kys7qkQ$LB=`@M#t7LMi%+5={bO`hV~QaKn0f! z^7DJ|%x+@K9b8^j*RR=cDhK^wpo~A%B*NXC+vxWF-=N0;fmLot^VCpS0_{(#sj1eS zV3P5XugNL9WQK*SdbOc(^&%HewC>#cJXIL39I^;qU1TyhWLS6X3c;^b?||s2X*vTvHjNykb*+*7*PQ&`_&{_5g^rHe^~P$~>(x}-r)uvsR(q#b zO-56z28YQQ;B18@4ua!a1_NdkmQB9)LF!)2_Yo8blCs4C3uSq=b#)X3nArTdPDtRfTQeI4(3>e3r%5o{wl{B8@KOq@N$Klr65Q3+RdDb%% z$!RXJEiz?Jn_-wT&bqbxF%!6~3{fnPDd?QY_(V-NV37cr6^C~Y%G`w_hEJL?Nd28<*WXG|m{SrT0OJv?sglcfK2NB`f~{T8U8fj|LAu8T+`x zha`n11Aba-Z#)vC26ja$G#s>0?Gu4f2nqnj$iS&5hh=z(TR17|j}f>8VzuOAV8~doy3IQPrNG0If0g_9=;? z+Fz+s(&aa1260SdRXr?hp@*>BXll_z%|XYc-WCfAxpHxt>CsjfX4!M=f=*z~{>SpJ zK31M$+k}3tw1f(Kiwo*@#S?#?HBi$J8||cBaazNtu#G6zk(Pt4hU?DYjN5t&2j1q( z>R0d0FMRm!`z7$~BUENr&9xmU#|LyXv>f7aqzpYm8-@n(USZ)-}ZEZmzh`>l7Rtxm>|`B9}3F z*~A|myri?q1;rnLRn(gW&3SH#uQf7)lQNUE))DY z#ht1>0-(ocg;2`cG8S0&(R*+K{H?~1?10-b6MCT1M*2}qotm}8Ua5oF zBfQ0pPWz?ypEy3BbK9EqnG0P|b%7p8`5)5<_!qF*qfR7ob37Q}N)~g#UZ`(5Woq36@m%Dd?!50T3*%^(XFMH_3HW z(T(i);rP8)-Ld5QehDn%%4zd&fha|g&j#K|#0oYC%1!bjNk0e3B{SGf6ZZqQxfhHY zfQ9>x@sfwsqzq%4xCsx`#u~_X&7Z*QBWR!?@$AC|@o*Wa&i$^1o^ow|R5`4Cy{g4m%=a^fr*?*nR8td^QVsZCnAB&R2)bJoF&Vk3~X4#Sw z5A6sk>v(K#o(GQ%rGj)=bddFfl+JwRTXJ8WY#1Hkx0p62eUwD>nzuN*!aBkxIiF}D zkT8mnjsov?AH0#hCo5);nCEE_vR;|5fSoHQHh`5}RgA0W4%pnx;7$aEQZY}g2b$R& zXKg#3xH7Q`*l~{bk0MS%g&bN=1b<(8PKawTb2$~Qvi&hJA@cwMJICV}7T6GB{wASe zwL%OfUxv)_PW@Kx;_?T%&}s9OB0vrQgV?Oab%OsEK5Q>=7tpgRBeJr$+qYx?4Ax*k z*VU@sZku*M=+ReQ#50r{LW4VJF$WOW1X)fIxO@M>N^`MY$kr%!aECHH7xV_~pr_)V zuttOX8a`T<91Ui*a6r4$Sguzq^_F%M?P~G1J_B*t;F5%!#i+y|NEH50RV!zig)xJJ9;Ya$d5$%=HxmUn#l6<$tv zHn&i2_et-&r+fST!NK2$Q&taaFRiUmwlJKms=jJ7^m^2qo}OvA8;r?Hs~c-iS^g=n z*O5BL-qvf0WLugcPzI?{c-k%ATw{R{zuLyBV=HdeU*d zN?}DTBZIy69eXiTt-2;yksku>m7C(Lczgv^jXUrJc@|u-Q3hbrZZq3UF0C|by4r@t zg#tlhW4?(Xj$I`PtVP~9a^xpcnE4jtk)2&W{_A9rk~EEGZH+7+ndQu&;?W2!S4dNT8?tm85uu2`sulCMQmjF?fm-V$hsBd+ z+7_KiBd^OeX9^pb1AE{#9-rDm!0)yBg@{qT8bPX8vA3|r1*%3xuF{ump~qYBh;yyW z!y$dfZc_O1uzR<O>wXbUDqZ|uuD-r=bNSxNGNNZd7JZMCM{vLEDJf*qpjTVG z&DPTBuqzv68tXb0i-DG2wq@M4ehIS1;`r7tp{pEh&guI!myPqFI7R~+xcIJL5psV2 zIfc&sgSP(Wf`rN?iilK)gx~&%qV6tZ(74xt$Q}uJ1+H)%Xu=edN*aAjr4rzpIqlCd zsn=sR;r#t)rXw)nGL_>uv3jk_;I;h&Mfv)r&p-EP>9IB~mu=jEx@3&S7=YrdLn&Tn zphklgS%s{2cEro|Xm1`Xx*~M5|@Z!Y|01K~P*r7^^_+ z6l;eb>Ngo2N*OB~B8Kn0y?80hvpYMGaCJE3U=>H())?<$hw%{`R0u#7#FY-+rmr#3c%SJ@U10-r;hZ&v6xap>k(G?Gr z3o{7lw74O5g%m3t8r*6eqp)l{%J~Ugq`iMY^G+`yAq?--DLesw@sY>0sVA0?xYKM;IzjKgth8%i-ch+$)Y#rNggbaRwiuBj6${NGp`V_Bh+Yoj9$X4yTZ_ zI@K4>x7@gcann!?@k%@<0ihR#ZB!_|L}JAUbkSRfL*jhEKnt(4n3^zFQya?W7NDD) z)bo7IW-}T@4My)V@L?a3N8onEX)Bkb3XN@>hZqVy{(~#}Kz@h_y44NX&fy^dgt_4)#FOqG6beNG7cl$C zg94GmL`nFm9c*X20#q$~UG|&J1CZVf3WW+<8FENj@^ZNk(cB&4=2Z9vyhnl!UUNIZ4zfYf zQPUgkz*osw#~K@t(CFBw7NNmZPdK!|{bs04L^I*DZcw9FE|4@jy$@l+r5!|@u>-0- z??~tws_*S_flQ!s+b#lYxJ7LU0bONRAWRmF>21=(a@fk%R%tVwKOJYz?3V)!YLAZ)N~ z#oD@qKmf7<==uZ(4-eZSV(f_oooZkym>OtWgBqd~v;_m+By;2FFeE3}0O&->NqqIw zVd3FF7E6c;t<+Dteo5-U7vI;FN`j(GZwBk=1ZpAuN5F0XNXz$mz(Zj3UB6FIl`6JuvfS7gu}VC$%e(N%o-W1^IOJ!mv!V-LmfRXO15SbdcY1(4JB{t z9LDrxNgGP=xLdN|sfQxsRQ+Sfl~*)Imt16u3=zZ14sydjZrkyja}>e)MAtA@*1D{MpHm$7K)!@MxF_^_+gAcn?QMCF1a&=}VB#?AAQ>2o z?2+9)3WTErIlhk2e-!5(fT(hCFcx=1rv2!IS37bde>M5Rd6Wu${rLwcyo1^PQeS+7Cc z!)B*$#z6yD)9aUX#;;#`H0Ibwo&hcg0s^jdb9uL>pK>9h8{EfAV6u58O1uLGQ7sf1 zJ{AlcL)pu01Y2dcd&9A@zzDhMg7D~L5CccbDZACuyggdL{2N{k-X4)atedl|;bf>2 zkoO0PPIyj+`>^BqoSb+u8CPmL)k|`|dc1tb*s>Uf#R><4nCJZh5)LKMqJ&D6bDTXW zh&HvIt717FOB&+877=XcjEvQuypx;di~?iGXgWy(fc+P-*BldK;-j$N!M4z3vQto- zPC%G?%;5VwF))?Omh!ue-_>!V1`uE2*7qiLV2gbEW1R~i!ED5I3OO?B-ZV@+1(+m0 zX`=5MMae`d!Fu625+lRm6oS&|WwQ1Q$=k__#(dhc;O&C}k?|Ys%uze(D@i+`5K zf5mGUlj3Ui7$<|Fc3wOd_F*1z2&;WrP;yiO=Z7 ziO;wThm$K+-6Q~EHZ}x-^-IWX3hwnSL&kp#Flijl06kboAS#ht%>WbA+ibE_QE7Y@OXWuI9@}X69n}P zKB`0wEuo{q0xa2<$E*l((;~^FBEupO2B^ZMvHIdySF>N_EC)CJcLu){eT>O~dCZJJ za4l&rKWPb5UzlVD-luLq?M2AP8k`C`mM$(Nb#^T%#l{CS>o6uUvuA0>k=n{vI}|`e zp<>B<7R)qIA|(=ejDs6HTkqsipVRc9o2zHyL>WQvW~cHwX5c6ZjC?pWL`{P1E%0LK zpy5;k;y=wvt$hO|&U*a`o95B{o`^){DqCL6Mvga)c zBoHP1wBFw#fZ}YZ<;oKAgtIrAAA_xMaiD#TZ7YE#PE_btIRBV3l`{ho>fXkPA_Gr1$AYP(@q7A-0Ap3c*_F*^zQOXvJd; zn?f8`6fZ0-Ib|^?c($gwca$J%oHWc9caIIkv4LF&>@(3?7!+vHzUgPA&#AOB?}DeV(1@ixb`m0dna@x8x-m zH&4wK1OV@HlM;YSD-7H7IluxF1;RZ6?A#l(5G@cA3jxt;?P^7w+u+LBgTaE3+Y1G# zdZT2SSV0nlWNYBGtFl0sE;!_Y*K2sAYdL427VSPN4W@R&HsCW%5%R(A6GAbMHki+W-9E(C3zDhrSHtesY#1lxlKo7<8Y_{99tt~!L@(BEFe4aw(f01! z-gQvazoXaS2<^M;5Q`k;j&(sP@(?V+E;Jo|(hkC31#BH8e_epkHGzN94geJP+BPll z;+8eg@Drc>p-^Cy z)YiA&gp^C8s4b@Fk|oeTjfkDtGxImpy2j$;;-TDOuT^2bMP)FTQ!%*<+WWlq{*?2# zHXtyaY(n^k_VSCZu3Wtq0|fv{x5$v5(PiZi$SD`H!U)k)XY=srU%^j*mXYpjY(X@LMFG;T zGk2>F-Y1_VTt$HTU`BUjk+O$N4aKn`yza>wxjIF3N1bz>GBK2pfq5$xl&UuqJX02s zAh#8w7(6K983k=sawMnZ1gUXcf+kjDLZpxiAyH~I#dF0g*|DnLCT|q0jEV_0kY8j{ zuiZ4z5zeOR_%JumQ77vd=|B``8yUh|*pif>HCjfACAg-+Fj9QU^4oGWVwr$)H4xDW z1JyhWW&OgSuxI%~F3n*VsY#<3sCpxyBy>w6YgQ-(xBVayV;+L-Z_@MN>LmiJ*Br7U z@Td?S!q1j^(mD=6hoYmgScS&|MgwT2(ty9u;S^xtI)u}-0H3xwF=07oJT{>}q5hi97468?n4iJ%W0sN*3OV6CTFq&23ZcBn zL>=J;VsgdACiTu5$fD!D{?4GTh*F29u)yB&Tg3?3TRu1TwL!iVgR07hHXBD4cAW2l zrlpiO_L|+~$gmqoEZWZ(jhKo{a+X=9hT&teW^f21yb_Zz+E$Z6vKS1I))_ZAkRCD# z!9YC?PNt(6VVB~y@|xU+#RjniOPRY-m#JdhxtlRayVg*Tkwel0(a4xkS>q374Gxos zx7u(k&LR*P70*qPh`K&U+u}7sTY&e5=~!dwrp!JLp+Q$ z7gor7Pp@6_c5%LMAzt1RRP15XB5meSIoPtPz`{4I=@Eep^fH`F8vhP0!>ttV`()TK zbh%G&1|pYf2^Af1re*s9F|}HNas2~(1rhJMPm0?kc4hn6wLg8}qSVZQ!RWHZ3{Z^} zA*spC-Y3I=k()^m6q>kJlI4^>6NU1)ZVYiz50tb~uD$&6^Aw2gR;_ad2kX zRUVYNltRe-?1XKn`ml_+Ovi?R(9b7;$L_oJ%9eqDI?frccnWrMIrsoF2~pV9N|yR< zh>U35n;SbSWdNhSpeC&%OcHGJ>FzE|wWVt8>Hhr#n6k8k>%zUQN3-}Vqau&}Rx#_FwKS~D^PbspJ) z4qvBx-HI2*uIgE>m%KF6Qyi&}6#hSKF5@hP9X6D!6NhW_k0gMMD5+( zBB~r`aG+TLgx`??w=M%H=&ntyFVQ%AJgVmqBF(KgA-4r*1uWfdX1B`L9&gP7QK$jR-ydzMqf8HKqe@<>N6Fs#U$BY}n)A1EKl<+Uo6rqq!8no-ql zVhl6q7Jy!`IKZS+bak=271Hn16es4qYm{L8-%$!2#;bQun7#_&>>kG<3p zcfEI44^v~EgCzhLQ+16P*aR>L6s;BQa6k>&60V+Na?n1TilHS~i_GZY>bWV^}o+qaU(c}hMTKb5SkUs7;E&516bRhgpaV=HX=Jnnc_+8TW_ zBh)RD!q`kY-sH)oF|eeelqGWVN&E^hW_+N@&Z2zo!RaO`5;VO56@p}TKm?ZNrc*~4 z4hVxcw&f7NTpp6fbb8LJx2`v*a@zZ{IMt*MS4;oVe+sGJ0)C3IaOS5v> z7D6({X%Mjz3Q6fjABx!zT%#V>i(QQ@(=>U z$|NF;1s-J6J^Xap5D-m)M)G9uNi-e~h&oN!kRo6zOTI!dQOf5u*rmU{*X7Dn*7b;~ zEn2bFQLLe))mTDt?5%{(yK!{F-Rg25EddLkl*-<4DAXI4xpT+1wrrmmPK0OxG4b?! zupYgLwph}2QL%F_b~a*!W1mJ=Ra($`FIHoMtm{NLK@*ax7n8*giDA^{_Wgv(k}*rL z%hZ(hB!(v|73&w8EH(BwBcz(G7CwSWgNtP6Kf+xbymrbe}j|#WV2QZ;_^4Mtoyz9g?TE|i21g(aq zc1qYy42_T7)ne|XvEsqZMl<6dD~^?ZEa^!x{Vxks8E+|dJ!^*~Ztf6MSvaZ*)cQa;Lg>%vBIA2LJ+%@N|3ul zy87?**|6m3fL z$q_E?FA_OMvM{_rFnpLaoCU#zzfLn_q<}3X3nc9UBM?Z0c)4kVz5)hh0;nhfc5}2$ zs|tKm-CYaia8FU1_Ff>H_}XJk{T;ZjN;f!|-n#S(}WC{Zd9<71UV|ehJDd5<=B6 zeAtCT($)zY%*K+fLLYd5jYFdRR zqD-NyShbN&?ypV1Tt`s|WL8uU&TchX-&uVUrNbuzK1D zGP>oci?Pslx>(AsJ)B>{fs{QfjSGL6j2F_$`jTd<2Yg5bR>o59>6Wwg7PF=htmXOYp*q;HrM`lYJ*4@6 zSv?rQ&8d!^ln^53e9TL|aIk_cVG z=k-2|7S|;B99SL54L@Ha*)J}SXPy@K-%zG);0+kxwzK68bJ3fdROQnKQ-UT>x)kEs zyqpy{0uY=&gF=LF(5-|v)-)a_f^Q$SX0BEnIAT22+F*mN4PIuk(Gv@%g{wfsA^A}y zA7ydxpmAj~;AxD<#!xr6*m<8?oK8L33R28(w!oZ1xAV1%a-+$Z7GkSooTR@&0kp@? zq5vA<>fW@jNOKn4kzao49(ce&Ve3zdbB*%w$^ z2yOqQdbjqPdmL;JNgoLOro)yv{u;6*EMlDxj@(_&Ne8io`iic7L=!qkv8+U4f+r-~ zJ<=%wK?Z|%gv1w2{HqpC?<&fGtQFVqB=i-YCq~XsPy~Bs?_IC{p1GJm{j{pV zmb?HVT%5R|tD{a@0|?Op*z46?^^W68VHPz$t>$0cz8#RLmSN$+w7^;SBu5lY8A`OF ze?R^hNFgnv4Xkj8h!K+?+9|wlmLTLte1s4f6E1$G6-Avyb zZxNO%+FAXC`=%rV0ujBe_srZJ9K4haFd)BNP4jNkl{D27qQ9k>BpK@-KGV#77rLwF z#>%Z(xwY~qzpkn_>6X{kvd?sVOlW>8C;;^vY!16$Ysnw#c-(`t&2rh%H@}r~|O}wykL> zmoCP(##k~xls09Vi&R82lN4eM@qKIW$WD;$L)Qtg#}B&@tXk`F!bPlD4hzSi zX*@9;$7+Pc2r(y+4VJC=^;v=AHf$R>eXb8&QDqrsXo!HZ1tO zb0{~cV}am{FMCCEOP9HzlPp3J9*JCnQ3Z(?#RQWx2%r&U2r>o9(I;dZSLOz@x-LN; z{E7*lnG&sy0_}VEZ!K>u-}_eiDAlF}a8A?FtaDmcAml?$ikOx?rF$e8X4&E4;4p>d z5Jw|6*PsK4&Kh90ZJ*kNo~d(IR(Ner*O#$`#OthBa`31agi%Qe2x|gCtZMzyP(P+*u9UgXGwl+|T z>psT+N-%-^`nckIto88v%9ZFTU=7#!j)6e|SldM~R^P9u(q3?o;414tRCo6l|i-7>y&nXUro|&Y2fc zx(K@Yn4J3&+1cMCQ20@XGIiafi?od8@02pb? znBS6JBx~OTcu3%`-&4wfVk);7?WdVitp$ob^*vA>Wd24RvXm`GjVWd^0QtJx-^FFj z;yN@W&^!k&m=!*z{>b!YMi@HbhvFSHd2Nl>)txkZ=kfa@( zFc&$@TA(edcLOE%$+`^m(Y40@+W?!qk*0HYO#sH4mzqL&X^ClnZ}UP1ii8{?dkNuf zv?a!Zsu#yBEp`QpkM7NOImV$Vn^rP?rB`S-44jlEj#@CpQL2}ulJfYt7;BVv5{aqPaq8kVszm$S9G}5H;%ozUiBes z4czE3QPrie93b8;g)xoldyP^9a7Q9!=1&Mc&`^QMuNFZTg1RvR=92RmvMqA^)8 zflaZOD;Ax9*Pf!avPd?F>`0Wt+;t~R>lpWB#D}YjzcVT;SyWRDTpf^fB%F$u zjb(k>k5#gHDhCPaNDZ0qgcl)WeB)EiCA@2JoUf{_a%2P?1SL;vN(on=Vk%`gwz4Be zuD}YWc@@QVl9ZRm(%e)si6&|Z0PqkTgJwN2D53SW_4P;V z_^*BSqeamFb6kLUrG>}SzRz5qIYG!#`wF&mXFhMC_}be1?1ztz7p`7^#k%Kscmxow zwa)DKOS6BvzCOzuS5S54ioJVueC;Y6)^E*;MFSraBj%ptkTy3UTGPL4eKy6;j0TG{ ztLN-z}Cwn;2u=ivz z9IV=!45x52{a5FP8f1$Z_vS3VYDUB7iwuru*WJ$(6*{s3u4A(Ey#0o3rn_CX`OM%=C4;(|x3%2Z>UI`UQ=rrm`ukG#0dI z2%D?jR}uu_%c?AkivU-O!$w6q>L55DYdvt>#LQRQvyC;&YL8J?SYM`{92!X~r&F=J z2zZ8n@yv3+?Sk{lVi~QKp)x#64m(z2k=B|wM5!`PVE5UQE=J*o?kOJH1a*aTr><%; zEc8V)y?)wNl(BWrtr=n(N1h?3FPag{M`$v|O{WE8$n$vt>Yk7+|EA1y4`Y^DqjdA3 zEzm?V$Vj>S`(xb0!Dv1wxag-q0Z%^}0)S)PBcmZa{bUURR=C7e#Cp_A<603R zCNhP%(CXMM0zKZW7sbsww)FdH*NdDP7d5ZPR*5R?DapcV5^~55(DOAS6T#)T&I(Qq zs^~487#ZwCN3TtrrlZCeZOI=ZCip{D5`URT2ESA`@SV&;{xDI8UzGoRgZaTf;NEF< z53yDDbrm#1yRn89yeN1TrEoub*_rCo+ylvyD$CZq#3P$)K_wW}66|q~)i6hFm>|{H zBKFKuwmuHA4}%_3sw3e;{Eqo1mtc$V$&T=Om%0A8a%qHfPuN+0F}h-dYSGs}Tu-6i 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-libs.fb0b7f4a.js b/priv/static/adminfe/static/js/chunk-libs.fb0b7f4a.js deleted file mode 100644 index e7f33e6c334479043fc86aca7af8c76179e7fbfb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204635 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 vlZjBvU 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¥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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/oAJy.840fb1c2.js.map b/priv/static/adminfe/static/js/oAJy.840fb1c2.js.map new file mode 100644 index 0000000000000000000000000000000000000000..48420eecd16f8e7ce273bc71f562ce26a469902b GIT binary patch literal 135594 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 JK@79+wL8pu+xKV;wJI0-7yqOAaZ%0 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 GX#aoH_pH(Y From 494bb6bac64361860db194aed57618450a76177d Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 23 Sep 2019 22:37:30 +0300 Subject: [PATCH 200/272] updated tests --- .../controllers/mastodon_api_controller.ex | 18 ++++----- .../web/mastodon_api/views/status_view.ex | 4 +- .../mastodon_api_controller_test.exs | 39 ++++++++++++------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 0c2b8dbb7..da74e4aa2 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -44,6 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.Scopes alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.RichMedia alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.ControllerHelper @@ -1530,19 +1531,16 @@ defp fetch_suggestion_id(attrs) do end end - def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do - with %Activity{} = activity <- Activity.get_by_id(status_id), + def status_card(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do - data = - StatusView.render( - "card.json", - Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - ) + data = RichMedia.Helpers.fetch_data_for_activity(activity) - json(conn, data) + conn + |> put_view(StatusView) + |> render("card.json", data) else - _e -> - json(conn, %{}) + _e -> {:error, :not_found} end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index ef796cddd..0450ed4d9 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -343,9 +343,7 @@ def render("card.json", %{rich_media: rich_media, page_url: page_url}) do } end - def render("card.json", _) do - nil - end + def render("card.json", _), do: nil def render("attachment.json", %{attachment: attachment}) do [attachment_url | _] = attachment["url"] diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 46e74fc75..14cd71aa8 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2798,6 +2798,18 @@ test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do %{user: user} end + test "returns empty result when rich_media disabled", %{conn: conn, user: user} do + Config.put([:rich_media, :enabled], false) + {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"}) + + response = + conn + |> get("/api/v1/statuses/#{activity.id}/card") + |> json_response(200) + + assert response == nil + end + test "returns rich-media card", %{conn: conn, user: user} do {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"}) @@ -2869,22 +2881,23 @@ test "replaces missing description with an empty string", %{conn: conn, user: us } end - test "returns empty object when id invalid", %{conn: conn} do - response = - conn - |> get("/api/v1/statuses/9eoozpwTul5mjSEDRI/card") - |> json_response(200) - - assert response == %{} + test "returns 404 response when id invalid", %{conn: conn} do + assert %{"error" => "Record not found"} = + conn + |> get("/api/v1/statuses/9eoozpwTul5mjSEDRI/card") + |> json_response(404) end - test "returns empty object when id isn't FlakeID", %{conn: conn} do - response = - conn - |> get("/api/v1/statuses/3ebbadd1-eb14-4e20-8118/card") - |> json_response(200) + test "returns 404 response when id isn't FlakeID", %{conn: conn} do + assert %{"error" => "Record not found"} = + conn + |> get("/api/v1/statuses/3ebbadd1-eb14-4e20-8118/card") + |> json_response(404) - assert response == %{} + assert %{"error" => "Record not found"} = + conn + |> get("/api/v1/statuses/8118/card") + |> json_response(404) end end From 63af6951fa42429d0a02861d5ad1afdd053864cf Mon Sep 17 00:00:00 2001 From: Rachel Fae Fox Date: Mon, 23 Sep 2019 20:38:53 +0000 Subject: [PATCH 201/272] add tunable for stream uploads, as needed for jortage to work. --- config/config.exs | 1 + config/description.exs | 6 ++++++ docs/config.md | 1 + lib/pleroma/uploaders/s3.ex | 22 ++++++++++++++++------ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/config/config.exs b/config/config.exs index 4c758d4a0..1988753d6 100644 --- a/config/config.exs +++ b/config/config.exs @@ -109,6 +109,7 @@ config :pleroma, Pleroma.Uploaders.S3, bucket: nil, + streaming_enabled: true, public_endpoint: "https://s3.amazonaws.com" config :pleroma, Pleroma.Uploaders.MDII, diff --git a/config/description.exs b/config/description.exs index 5dc8dc364..d95250017 100644 --- a/config/description.exs +++ b/config/description.exs @@ -110,6 +110,12 @@ description: "If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or \"\" etc." <> " For example, when using CDN to S3 virtual host format, set \"\". At this time, write CNAME to CDN in public_endpoint." + }, + %{ + key: :streaming_enabled, + type: :boolean, + description: + "Enable streaming uploads, when enabled the file will be sent to the server in chunks as it's being read. This may be unsupported by some providers, try disabling this if you have upload problems." } ] }, diff --git a/docs/config.md b/docs/config.md index 1179def56..34e9c19ec 100644 --- a/docs/config.md +++ b/docs/config.md @@ -23,6 +23,7 @@ Note: `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`. * `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc. For example, when using CDN to S3 virtual host format, set "". At this time, write CNAME to CDN in public_endpoint. +* `streaming_enabled`: Enable streaming uploads, when enabled the file will be sent to the server in chunks as it's being read. This may be unsupported by some providers, try disabling this if you have upload problems. ## Pleroma.Upload.Filter.Mogrify diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex index 8c353bed3..9876b6398 100644 --- a/lib/pleroma/uploaders/s3.ex +++ b/lib/pleroma/uploaders/s3.ex @@ -38,16 +38,26 @@ def get_file(file) do def put_file(%Pleroma.Upload{} = upload) do config = Config.get([__MODULE__]) bucket = Keyword.get(config, :bucket) + streaming = Keyword.get(config, :streaming_enabled) s3_name = strict_encode(upload.path) op = - upload.tempfile - |> ExAws.S3.Upload.stream_file() - |> ExAws.S3.upload(bucket, s3_name, [ - {:acl, :public_read}, - {:content_type, upload.content_type} - ]) + if streaming do + upload.tempfile + |> ExAws.S3.Upload.stream_file() + |> ExAws.S3.upload(bucket, s3_name, [ + {:acl, :public_read}, + {:content_type, upload.content_type} + ]) + else + {:ok, file_data} = File.read(upload.tempfile) + + ExAws.S3.put_object(bucket, s3_name, file_data, [ + {:acl, :public_read}, + {:content_type, upload.content_type} + ]) + end case ExAws.request(op) do {:ok, _} -> From e63f167f013c1c159c40745ee44535c65b999ffb Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 24 Sep 2019 00:37:27 +0300 Subject: [PATCH 202/272] Also pretty print pack.json --- lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index 6beca426a..3ad29bd38 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -242,7 +242,7 @@ def create(conn, %{"name" => name}) do File.write!( pack_file_p, - Jason.encode!(%{pack: %{}, files: %{}}) + Jason.encode!(%{pack: %{}, files: %{}}, pretty: true) ) conn |> json("ok") From e1d2d69c8799cb6d3efbdc28d9e98867da76b4c2 Mon Sep 17 00:00:00 2001 From: Steven Fuchs Date: Mon, 23 Sep 2019 22:33:59 +0000 Subject: [PATCH 203/272] Clean up views --- .../activity_pub/activity_pub_controller.ex | 36 ++++++++++++------- .../web/activity_pub/views/object_view.ex | 4 +-- .../web/admin_api/admin_api_controller.ex | 20 +++++++---- lib/pleroma/web/admin_api/report.ex | 22 ++++++++++++ .../web/admin_api/views/report_view.ex | 18 ++++------ .../controllers/search_controller.ex | 5 +-- lib/pleroma/web/ostatus/ostatus_controller.ex | 3 +- test/web/admin_api/views/report_view_test.exs | 15 ++++---- 8 files changed, 81 insertions(+), 42 deletions(-) create mode 100644 lib/pleroma/web/admin_api/report.ex diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 01b34fb1d..9eb86106f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -49,7 +49,8 @@ def user(conn, %{"nickname" => nickname}) do {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("user.json", %{user: user})) + |> put_view(UserView) + |> render("user.json", %{user: user}) else nil -> {:error, :not_found} end @@ -90,7 +91,8 @@ def object_likes(conn, %{"uuid" => uuid, "page" => page}) do conn |> put_resp_content_type("application/activity+json") - |> json(ObjectView.render("likes.json", ap_id, likes, page)) + |> put_view(ObjectView) + |> render("likes.json", %{ap_id: ap_id, likes: likes, page: page}) else {:public?, false} -> {:error, :not_found} @@ -104,7 +106,8 @@ def object_likes(conn, %{"uuid" => uuid}) do likes <- Utils.get_object_likes(object) do conn |> put_resp_content_type("application/activity+json") - |> json(ObjectView.render("likes.json", ap_id, likes)) + |> put_view(ObjectView) + |> render("likes.json", %{ap_id: ap_id, likes: likes}) else {:public?, false} -> {:error, :not_found} @@ -158,7 +161,8 @@ defp set_cache_ttl_for(conn, entity) do def following(%{assigns: %{relay: true}} = conn, _params) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("following.json", %{user: Relay.get_actor()})) + |> put_view(UserView) + |> render("following.json", %{user: Relay.get_actor()}) end def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do @@ -170,7 +174,8 @@ def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "p conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("following.json", %{user: user, page: page, for: for_user})) + |> put_view(UserView) + |> render("following.json", %{user: user, page: page, for: for_user}) else {:show_follows, _} -> conn @@ -184,7 +189,8 @@ def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname}) d {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("following.json", %{user: user, for: for_user})) + |> put_view(UserView) + |> render("following.json", %{user: user, for: for_user}) end end @@ -192,7 +198,8 @@ def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname}) d def followers(%{assigns: %{relay: true}} = conn, _params) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("followers.json", %{user: Relay.get_actor()})) + |> put_view(UserView) + |> render("followers.json", %{user: Relay.get_actor()}) end def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do @@ -204,7 +211,8 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "p conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("followers.json", %{user: user, page: page, for: for_user})) + |> put_view(UserView) + |> render("followers.json", %{user: user, page: page, for: for_user}) else {:show_followers, _} -> conn @@ -218,7 +226,8 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname}) d {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("followers.json", %{user: user, for: for_user})) + |> put_view(UserView) + |> render("followers.json", %{user: user, for: for_user}) end end @@ -227,7 +236,8 @@ def outbox(conn, %{"nickname" => nickname} = params) do {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("outbox.json", %{user: user, max_id: params["max_id"]})) + |> put_view(UserView) + |> render("outbox.json", %{user: user, max_id: params["max_id"]}) end end @@ -275,7 +285,8 @@ defp represent_service_actor(%User{} = user, conn) do with {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("user.json", %{user: user})) + |> put_view(UserView) + |> render("user.json", %{user: user}) else nil -> {:error, :not_found} end @@ -296,7 +307,8 @@ def internal_fetch(conn, _params) do def whoami(%{assigns: %{user: %User{} = user}} = conn, _params) do conn |> put_resp_content_type("application/activity+json") - |> json(UserView.render("user.json", %{user: user})) + |> put_view(UserView) + |> render("user.json", %{user: user}) end def whoami(_conn, _params), do: {:error, :not_found} diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index 94d05f49b..0d63f0707 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -37,12 +37,12 @@ def render("object.json", %{object: %Activity{} = activity}) do Map.merge(base, additional) end - def render("likes.json", ap_id, likes, page) do + def render("likes.json", %{ap_id: ap_id, likes: likes, page: page}) do collection(likes, "#{ap_id}/likes", page) |> Map.merge(Pleroma.Web.ActivityPub.Utils.make_json_ld_header()) end - def render("likes.json", ap_id, likes) do + def render("likes.json", %{ap_id: ap_id, likes: likes}) do %{ "id" => "#{ap_id}/likes", "type" => "OrderedCollection", diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 4d4e862dd..251bb1012 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -14,6 +14,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.AdminAPI.Config alias Pleroma.Web.AdminAPI.ConfigView alias Pleroma.Web.AdminAPI.ModerationLogView + alias Pleroma.Web.AdminAPI.Report alias Pleroma.Web.AdminAPI.ReportView alias Pleroma.Web.AdminAPI.Search alias Pleroma.Web.CommonAPI @@ -139,7 +140,8 @@ def users_create(%{assigns: %{user: admin}} = conn, %{"users" => users}) do def user_show(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do conn - |> json(AccountView.render("show.json", %{user: user})) + |> put_view(AccountView) + |> render("show.json", %{user: user}) else _ -> {:error, :not_found} end @@ -158,7 +160,8 @@ def list_user_statuses(conn, %{"nickname" => nickname} = params) do }) conn - |> json(StatusView.render("index.json", %{activities: activities, as: :activity})) + |> put_view(StatusView) + |> render("index.json", %{activities: activities, as: :activity}) else _ -> {:error, :not_found} end @@ -178,7 +181,8 @@ def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => ni }) conn - |> json(AccountView.render("show.json", %{user: updated_user})) + |> put_view(AccountView) + |> render("show.json", %{user: updated_user}) end def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do @@ -424,7 +428,8 @@ def invites(conn, _params) do invites = UserInviteToken.list_invites() conn - |> json(AccountView.render("invites.json", %{invites: invites})) + |> put_view(AccountView) + |> render("invites.json", %{invites: invites}) end @doc "Revokes invite by token" @@ -432,7 +437,8 @@ def revoke_invite(conn, %{"token" => token}) do with {:ok, invite} <- UserInviteToken.find_by_token(token), {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do conn - |> json(AccountView.render("invite.json", %{invite: updated_invite})) + |> put_view(AccountView) + |> render("invite.json", %{invite: updated_invite}) else nil -> {:error, :not_found} end @@ -465,7 +471,7 @@ def report_show(conn, %{"id" => id}) do with %Activity{} = report <- Activity.get_by_id(id) do conn |> put_view(ReportView) - |> render("show.json", %{report: report}) + |> render("show.json", Report.extract_report_info(report)) else _ -> {:error, :not_found} end @@ -481,7 +487,7 @@ def report_update_state(%{assigns: %{user: admin}} = conn, %{"id" => id, "state" conn |> put_view(ReportView) - |> render("show.json", %{report: report}) + |> render("show.json", Report.extract_report_info(report)) end end diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex new file mode 100644 index 000000000..c751dc2be --- /dev/null +++ b/lib/pleroma/web/admin_api/report.ex @@ -0,0 +1,22 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.Report do + alias Pleroma.Activity + alias Pleroma.User + + def extract_report_info( + %{data: %{"actor" => actor, "object" => [account_ap_id | status_ap_ids]}} = report + ) do + user = User.get_cached_by_ap_id(actor) + account = User.get_cached_by_ap_id(account_ap_id) + + statuses = + Enum.map(status_ap_ids, fn ap_id -> + Activity.get_by_ap_id_with_object(ap_id) + end) + + %{report: report, user: user, account: account, statuses: statuses} + end +end diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index 51b95ad5e..8c06364a3 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -4,27 +4,26 @@ defmodule Pleroma.Web.AdminAPI.ReportView do use Pleroma.Web, :view - alias Pleroma.Activity alias Pleroma.HTML alias Pleroma.User + alias Pleroma.Web.AdminAPI.Report alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.MastodonAPI.StatusView def render("index.json", %{reports: reports}) do %{ reports: - render_many(reports[:items], __MODULE__, "show.json", as: :report) |> Enum.reverse(), + reports[:items] + |> Enum.map(&Report.extract_report_info(&1)) + |> Enum.map(&render(__MODULE__, "show.json", &1)) + |> Enum.reverse(), total: reports[:total] } end - def render("show.json", %{report: report}) do - user = User.get_cached_by_ap_id(report.data["actor"]) + def render("show.json", %{report: report, user: user, account: account, statuses: statuses}) do created_at = Utils.to_masto_date(report.data["published"]) - [account_ap_id | status_ap_ids] = report.data["object"] - account = User.get_cached_by_ap_id(account_ap_id) - content = unless is_nil(report.data["content"]) do HTML.filter_tags(report.data["content"]) @@ -32,11 +31,6 @@ def render("show.json", %{report: report}) do nil end - statuses = - Enum.map(status_ap_ids, fn ap_id -> - Activity.get_by_ap_id_with_object(ap_id) - end) - %{ id: report.id, account: merge_account_views(account), diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 9072aa7a4..c91713773 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -19,9 +19,10 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do accounts = User.search(query, search_options(params, user)) - res = AccountView.render("accounts.json", users: accounts, for: user, as: :user) - json(conn, res) + conn + |> put_view(AccountView) + |> render("accounts.json", users: accounts, for: user, as: :user) end def search2(conn, params), do: do_search(:v2, conn, params) diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 64b2c64b3..8f325b28e 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -216,7 +216,8 @@ defp represent_activity( conn |> put_resp_header("content-type", "application/activity+json") - |> json(ObjectView.render("object.json", %{object: object})) + |> put_view(ObjectView) + |> render("object.json", %{object: object}) end defp represent_activity(_conn, "activity+json", _, _) do diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs index a00c9c579..40df01101 100644 --- a/test/web/admin_api/views/report_view_test.exs +++ b/test/web/admin_api/views/report_view_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do use Pleroma.DataCase import Pleroma.Factory + alias Pleroma.Web.AdminAPI.Report alias Pleroma.Web.AdminAPI.ReportView alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView @@ -34,7 +35,7 @@ test "renders a report" do } result = - ReportView.render("show.json", %{report: activity}) + ReportView.render("show.json", Report.extract_report_info(activity)) |> Map.delete(:created_at) assert result == expected @@ -66,7 +67,7 @@ test "includes reported statuses" do } result = - ReportView.render("show.json", %{report: report_activity}) + ReportView.render("show.json", Report.extract_report_info(report_activity)) |> Map.delete(:created_at) assert result == expected @@ -78,7 +79,9 @@ test "renders report's state" do {:ok, activity} = CommonAPI.report(user, %{"account_id" => other_user.id}) {:ok, activity} = CommonAPI.update_report_state(activity.id, "closed") - assert %{state: "closed"} = ReportView.render("show.json", %{report: activity}) + + assert %{state: "closed"} = + ReportView.render("show.json", Report.extract_report_info(activity)) end test "renders report description" do @@ -92,7 +95,7 @@ test "renders report description" do }) assert %{content: "posts are too good for this instance"} = - ReportView.render("show.json", %{report: activity}) + ReportView.render("show.json", Report.extract_report_info(activity)) end test "sanitizes report description" do @@ -109,7 +112,7 @@ test "sanitizes report description" do activity = Map.put(activity, :data, data) refute "" == - ReportView.render("show.json", %{report: activity})[:content] + ReportView.render("show.json", Report.extract_report_info(activity))[:content] end test "doesn't error out when the user doesn't exists" do @@ -125,6 +128,6 @@ test "doesn't error out when the user doesn't exists" do Pleroma.User.delete(other_user) Pleroma.User.invalidate_cache(other_user) - assert %{} = ReportView.render("show.json", %{report: activity}) + assert %{} = ReportView.render("show.json", Report.extract_report_info(activity)) end end From 79b25be4e1e9e97277a831c98ccea86a038914de Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 24 Sep 2019 14:16:52 +0700 Subject: [PATCH 204/272] Do not return tuple when unneeded --- lib/mix/tasks/pleroma/user.ex | 8 +-- lib/pleroma/user.ex | 72 ++++++++----------- lib/pleroma/web/activity_pub/publisher.ex | 4 +- .../controllers/mastodon_api_controller.ex | 10 +-- test/user_test.exs | 22 +++--- 5 files changed, 53 insertions(+), 63 deletions(-) diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index eb0052144..84c923901 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -228,9 +228,9 @@ def run(["unsubscribe", nickname]) do shell_info("Deactivating #{user.nickname}") User.deactivate(user) - {:ok, friends} = User.get_friends(user) - - Enum.each(friends, fn friend -> + user + |> User.get_friends() + |> Enum.each(fn friend -> user = User.get_cached_by_id(user.id) shell_info("Unsubscribing #{friend.nickname} from #{user.nickname}") @@ -405,7 +405,7 @@ def run(["delete_activities", nickname]) do start_pleroma() with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do - {:ok, _} = User.delete_user_activities(user) + User.delete_user_activities(user) shell_info("User #{nickname} statuses deleted.") else _ -> diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ab253a274..8d126933b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -685,9 +685,9 @@ def get_followers_query(user), do: get_followers_query(user, nil) @spec get_followers(User.t(), pos_integer()) :: {:ok, list(User.t())} def get_followers(user, page \\ nil) do - q = get_followers_query(user, page) - - {:ok, Repo.all(q)} + user + |> get_followers_query(page) + |> Repo.all() end @spec get_external_followers(User.t(), pos_integer()) :: {:ok, list(User.t())} @@ -720,9 +720,9 @@ def get_friends_query(user, page) do def get_friends_query(user), do: get_friends_query(user, nil) def get_friends(user, page \\ nil) do - q = get_friends_query(user, page) - - {:ok, Repo.all(q)} + user + |> get_friends_query(page) + |> Repo.all() end def get_friends_ids(user, page \\ nil) do @@ -733,15 +733,13 @@ def get_friends_ids(user, page \\ nil) do @spec get_follow_requests(User.t()) :: {:ok, [User.t()]} def get_follow_requests(%User{} = user) do - users = - Activity.follow_requests_for_actor(user) - |> join(:inner, [a], u in User, on: a.actor == u.ap_id) - |> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address])) - |> group_by([a, u], u.id) - |> select([a, u], u) - |> Repo.all() - - {:ok, users} + user + |> Activity.follow_requests_for_actor() + |> join(:inner, [a], u in User, on: a.actor == u.ap_id) + |> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address])) + |> group_by([a, u], u.id) + |> select([a, u], u) + |> Repo.all() end def increase_note_count(%User{} = user) do @@ -1104,15 +1102,13 @@ def deactivate_async(user, status \\ true) do def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - with {:ok, friends} <- User.get_friends(user), - {:ok, followers} <- User.get_followers(user), - {:ok, user} <- + with {:ok, user} <- user |> change() |> put_embed(:info, info_cng) |> update_and_set_cache() do - Enum.each(followers, &invalidate_cache(&1)) - Enum.each(friends, &update_follower_count(&1)) + Enum.each(get_followers(user), &invalidate_cache/1) + Enum.each(get_friends(user), &update_follower_count/1) {:ok, user} end @@ -1137,18 +1133,18 @@ def perform(:delete, %User{} = user) do {:ok, _user} = ActivityPub.delete(user) # Remove all relationships - {:ok, followers} = User.get_followers(user) - - Enum.each(followers, fn follower -> + user + |> get_followers() + |> Enum.each(fn follower -> ActivityPub.unfollow(follower, user) - User.unfollow(follower, user) + unfollow(follower, user) end) - {:ok, friends} = User.get_friends(user) - - Enum.each(friends, fn followed -> + user + |> get_friends() + |> Enum.each(fn followed -> ActivityPub.unfollow(user, followed) - User.unfollow(user, followed) + unfollow(user, followed) end) delete_user_activities(user) @@ -1160,13 +1156,11 @@ def perform(:delete, %User{} = user) do def perform(:fetch_initial_posts, %User{} = user) do pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) - Enum.each( - # Insert all the posts in reverse order, so they're in the right order on the timeline - Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), - &Pleroma.Web.Federator.incoming_ap_doc/1 - ) - - {:ok, user} + # Insert all the posts in reverse order, so they're in the right order on the timeline + user.info.source_data["outbox"] + |> Utils.fetch_ordered_collection(pages) + |> Enum.reverse() + |> Enum.each(&Pleroma.Web.Federator.incoming_ap_doc/1) end def perform(:deactivate_async, user, status), do: deactivate(user, status) @@ -1252,16 +1246,12 @@ def follow_import(%User{} = follower, followed_identifiers) }) end - def delete_user_activities(%User{ap_id: ap_id} = user) do + def delete_user_activities(%User{ap_id: ap_id}) do ap_id |> Activity.Queries.by_actor() |> RepoStreamer.chunk_stream(50) - |> Stream.each(fn activities -> - Enum.each(activities, &delete_activity(&1)) - end) + |> Stream.each(fn activities -> Enum.each(activities, &delete_activity/1) end) |> Stream.run() - - {:ok, user} end defp delete_activity(%{data: %{"type" => "Create"}} = activity) do diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 114251b24..3866dacee 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -111,11 +111,11 @@ defp should_federate?(inbox, public) do @spec recipients(User.t(), Activity.t()) :: list(User.t()) | [] defp recipients(actor, activity) do - {:ok, followers} = + followers = if actor.follower_address in activity.recipients do User.get_external_followers(actor) else - {:ok, []} + [] end fetchers = diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 6421c2c53..270c74089 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -958,11 +958,11 @@ def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do end def follow_requests(%{assigns: %{user: followed}} = conn, _params) do - with {:ok, follow_requests} <- User.get_follow_requests(followed) do - conn - |> put_view(AccountView) - |> render("accounts.json", %{for: followed, users: follow_requests, as: :user}) - end + follow_requests = User.get_follow_requests(followed) + + conn + |> put_view(AccountView) + |> render("accounts.json", %{for: followed, users: follow_requests, as: :user}) end def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do diff --git a/test/user_test.exs b/test/user_test.exs index aebe7aa06..21ea1d28e 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -74,8 +74,8 @@ test "returns all pending follow requests" do CommonAPI.follow(follower, unlocked) CommonAPI.follow(follower, locked) - assert {:ok, []} = User.get_follow_requests(unlocked) - assert {:ok, [activity]} = User.get_follow_requests(locked) + assert [] = User.get_follow_requests(unlocked) + assert [activity] = User.get_follow_requests(locked) assert activity end @@ -90,7 +90,7 @@ test "doesn't return already accepted or duplicate follow requests" do CommonAPI.follow(accepted_follower, locked) User.follow(accepted_follower, locked) - assert {:ok, [activity]} = User.get_follow_requests(locked) + assert [activity] = User.get_follow_requests(locked) assert activity end @@ -99,10 +99,10 @@ test "clears follow requests when requester is blocked" do follower = insert(:user) CommonAPI.follow(follower, followed) - assert {:ok, [_activity]} = User.get_follow_requests(followed) + assert [_activity] = User.get_follow_requests(followed) {:ok, _follower} = User.block(followed, follower) - assert {:ok, []} = User.get_follow_requests(followed) + assert [] = User.get_follow_requests(followed) end test "follow_all follows mutliple users" do @@ -560,7 +560,7 @@ test "it sets the follower_adress" do test "it enforces the fqn format for nicknames" do cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"}) - assert cs.changes.local == false + assert Ecto.Changeset.get_field(cs, :local) == false assert cs.changes.avatar refute cs.valid? end @@ -584,7 +584,7 @@ test "gets all followers for a given user" do {:ok, follower_one} = User.follow(follower_one, user) {:ok, follower_two} = User.follow(follower_two, user) - {:ok, res} = User.get_followers(user) + res = User.get_followers(user) assert Enum.member?(res, follower_one) assert Enum.member?(res, follower_two) @@ -600,7 +600,7 @@ test "gets all friends (followed users) for a given user" do {:ok, user} = User.follow(user, followed_one) {:ok, user} = User.follow(user, followed_two) - {:ok, res} = User.get_friends(user) + res = User.get_friends(user) followed_one = User.get_cached_by_ap_id(followed_one.ap_id) followed_two = User.get_cached_by_ap_id(followed_two.ap_id) @@ -975,7 +975,7 @@ test "hide a user from followers " do info = User.get_cached_user_info(user2) assert info.follower_count == 0 - assert {:ok, []} = User.get_followers(user2) + assert [] = User.get_followers(user2) end test "hide a user from friends" do @@ -991,7 +991,7 @@ test "hide a user from friends" do assert info.following_count == 0 assert User.following_count(user2) == 0 - assert {:ok, []} = User.get_friends(user2) + assert [] = User.get_friends(user2) end test "hide a user's statuses from timelines and notifications" do @@ -1034,7 +1034,7 @@ test "hide a user's statuses from timelines and notifications" do test ".delete_user_activities deletes all create activities", %{user: user} do {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"}) - {:ok, _} = User.delete_user_activities(user) + User.delete_user_activities(user) # TODO: Remove favorites, repeats, delete activities. refute Activity.get_by_id(activity.id) From a66a7a328ffe908bda4e8453111559aa7cd579a6 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 24 Sep 2019 15:16:44 +0700 Subject: [PATCH 205/272] Extract notification actions from `MastodonAPIController` into `NotificationController` --- .../controllers/mastodon_api_controller.ex | 45 --- .../controllers/notification_controller.ex | 57 ++++ lib/pleroma/web/router.ex | 10 +- .../notification_controller_test.exs | 299 ++++++++++++++++++ .../mastodon_api_controller_test.exs | 293 ----------------- 5 files changed, 361 insertions(+), 343 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/notification_controller.ex create mode 100644 test/web/mastodon_api/controllers/notification_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 6421c2c53..1d53f7509 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -16,7 +16,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Filter alias Pleroma.Formatter alias Pleroma.HTTP - alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Pagination alias Pleroma.Plugs.RateLimiter @@ -35,7 +34,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI alias Pleroma.Web.MastodonAPI.MastodonView - alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.ReportView alias Pleroma.Web.MastodonAPI.ScheduledActivityView alias Pleroma.Web.MastodonAPI.StatusView @@ -722,49 +720,6 @@ def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do end end - def notifications(%{assigns: %{user: user}} = conn, params) do - notifications = MastodonAPI.get_notifications(user, params) - - conn - |> add_link_headers(notifications) - |> put_view(NotificationView) - |> render("index.json", %{notifications: notifications, for: user}) - end - - def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do - with {:ok, notification} <- Notification.get(user, id) do - conn - |> put_view(NotificationView) - |> render("show.json", %{notification: notification, for: user}) - else - {:error, reason} -> - conn - |> put_status(:forbidden) - |> json(%{"error" => reason}) - end - end - - def clear_notifications(%{assigns: %{user: user}} = conn, _params) do - Notification.clear(user) - json(conn, %{}) - end - - def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do - with {:ok, _notif} <- Notification.dismiss(user, id) do - json(conn, %{}) - else - {:error, reason} -> - conn - |> put_status(:forbidden) - |> json(%{"error" => reason}) - end - end - - def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do - Notification.destroy_multiple(user, ids) - json(conn, %{}) - end - def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do id = List.wrap(id) q = from(u in User, where: u.id in ^id) diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex new file mode 100644 index 000000000..7e4d7297c --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex @@ -0,0 +1,57 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.NotificationController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + + alias Pleroma.Notification + alias Pleroma.Web.MastodonAPI.MastodonAPI + + # GET /api/v1/notifications + def index(%{assigns: %{user: user}} = conn, params) do + notifications = MastodonAPI.get_notifications(user, params) + + conn + |> add_link_headers(notifications) + |> render("index.json", notifications: notifications, for: user) + end + + # GET /api/v1/notifications/:id + def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with {:ok, notification} <- Notification.get(user, id) do + render(conn, "show.json", notification: notification, for: user) + else + {:error, reason} -> + conn + |> put_status(:forbidden) + |> json(%{"error" => reason}) + end + end + + # POST /api/v1/notifications/clear + def clear(%{assigns: %{user: user}} = conn, _params) do + Notification.clear(user) + json(conn, %{}) + end + + # POST /api/v1/notifications/dismiss + def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do + with {:ok, _notif} <- Notification.dismiss(user, id) do + json(conn, %{}) + else + {:error, reason} -> + conn + |> put_status(:forbidden) + |> json(%{"error" => reason}) + end + end + + # DELETE /api/v1/notifications/destroy_multiple + def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do + Notification.destroy_multiple(user, ids) + json(conn, %{}) + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e583093d2..9fee5beac 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -324,11 +324,11 @@ defmodule Pleroma.Web.Router do get("/favourites", MastodonAPIController, :favourites) get("/bookmarks", MastodonAPIController, :bookmarks) - post("/notifications/clear", MastodonAPIController, :clear_notifications) - post("/notifications/dismiss", MastodonAPIController, :dismiss_notification) - get("/notifications", MastodonAPIController, :notifications) - get("/notifications/:id", MastodonAPIController, :get_notification) - delete("/notifications/destroy_multiple", MastodonAPIController, :destroy_multiple) + get("/notifications", NotificationController, :index) + get("/notifications/:id", NotificationController, :show) + post("/notifications/clear", NotificationController, :clear) + post("/notifications/dismiss", NotificationController, :dismiss) + delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple) get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses) get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status) diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs new file mode 100644 index 000000000..e4137e92c --- /dev/null +++ b/test/web/mastodon_api/controllers/notification_controller_test.exs @@ -0,0 +1,299 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Notification + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.Web.CommonAPI + + import Pleroma.Factory + + test "list of notifications", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + + {:ok, [_notification]} = Notification.create_notifications(activity) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/notifications") + + expected_response = + "hi @#{user.nickname}" + + assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) + assert response == expected_response + end + + test "getting a single notification", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + + {:ok, [notification]} = Notification.create_notifications(activity) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/notifications/#{notification.id}") + + expected_response = + "hi @#{user.nickname}" + + assert %{"status" => %{"content" => response}} = json_response(conn, 200) + assert response == expected_response + end + + test "dismissing a single notification", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + + {:ok, [notification]} = Notification.create_notifications(activity) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/notifications/dismiss", %{"id" => notification.id}) + + assert %{} = json_response(conn, 200) + end + + test "clearing all notifications", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + + {:ok, [_notification]} = Notification.create_notifications(activity) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/notifications/clear") + + assert %{} = json_response(conn, 200) + + conn = + build_conn() + |> assign(:user, user) + |> get("/api/v1/notifications") + + assert all = json_response(conn, 200) + assert all == [] + end + + test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + + notification1_id = get_notification_id_by_activity(activity1) + notification2_id = get_notification_id_by_activity(activity2) + notification3_id = get_notification_id_by_activity(activity3) + notification4_id = get_notification_id_by_activity(activity4) + + conn = assign(conn, :user, user) + + # min_id + result = + conn + |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}") + |> json_response(:ok) + + assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + + # since_id + result = + conn + |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}") + |> json_response(:ok) + + assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + + # max_id + result = + conn + |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}") + |> json_response(:ok) + + assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + end + + test "filters notifications using exclude_types", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"}) + {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"}) + {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user) + {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) + {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) + + mention_notification_id = get_notification_id_by_activity(mention_activity) + favorite_notification_id = get_notification_id_by_activity(favorite_activity) + reblog_notification_id = get_notification_id_by_activity(reblog_activity) + follow_notification_id = get_notification_id_by_activity(follow_activity) + + conn = assign(conn, :user, user) + + conn_res = + get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]}) + + assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200) + + conn_res = + get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]}) + + assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200) + + conn_res = + get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]}) + + assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200) + + conn_res = + get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]}) + + assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200) + end + + test "destroy multiple", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) + {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) + + notification1_id = get_notification_id_by_activity(activity1) + notification2_id = get_notification_id_by_activity(activity2) + notification3_id = get_notification_id_by_activity(activity3) + notification4_id = get_notification_id_by_activity(activity4) + + conn = assign(conn, :user, user) + + result = + conn + |> get("/api/v1/notifications") + |> json_response(:ok) + + assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result + + conn2 = + conn + |> assign(:user, other_user) + + result = + conn2 + |> get("/api/v1/notifications") + |> json_response(:ok) + + assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + + conn_destroy = + conn + |> delete("/api/v1/notifications/destroy_multiple", %{ + "ids" => [notification1_id, notification2_id] + }) + + assert json_response(conn_destroy, 200) == %{} + + result = + conn2 + |> get("/api/v1/notifications") + |> json_response(:ok) + + assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + end + + test "doesn't see notifications after muting user with notifications", %{conn: conn} do + user = insert(:user) + user2 = insert(:user) + + {:ok, _, _, _} = CommonAPI.follow(user, user2) + {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) + + conn = assign(conn, :user, user) + + conn = get(conn, "/api/v1/notifications") + + assert length(json_response(conn, 200)) == 1 + + {:ok, user} = User.mute(user, user2) + + conn = assign(build_conn(), :user, user) + conn = get(conn, "/api/v1/notifications") + + assert json_response(conn, 200) == [] + end + + test "see notifications after muting user without notifications", %{conn: conn} do + user = insert(:user) + user2 = insert(:user) + + {:ok, _, _, _} = CommonAPI.follow(user, user2) + {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) + + conn = assign(conn, :user, user) + + conn = get(conn, "/api/v1/notifications") + + assert length(json_response(conn, 200)) == 1 + + {:ok, user} = User.mute(user, user2, false) + + conn = assign(build_conn(), :user, user) + conn = get(conn, "/api/v1/notifications") + + assert length(json_response(conn, 200)) == 1 + end + + test "see notifications after muting user with notifications and with_muted parameter", %{ + conn: conn + } do + user = insert(:user) + user2 = insert(:user) + + {:ok, _, _, _} = CommonAPI.follow(user, user2) + {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) + + conn = assign(conn, :user, user) + + conn = get(conn, "/api/v1/notifications") + + assert length(json_response(conn, 200)) == 1 + + {:ok, user} = User.mute(user, user2) + + conn = assign(build_conn(), :user, user) + conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"}) + + assert length(json_response(conn, 200)) == 1 + end + + defp get_notification_id_by_activity(%{id: id}) do + Notification + |> Repo.get_by(activity_id: id) + |> Map.get(:id) + |> to_string() + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 73a3bf135..0eb78fe5b 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -999,299 +999,6 @@ test "list timeline does not leak non-public statuses for unfollowed users", %{c end end - describe "notifications" do - test "list of notifications", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - - {:ok, [_notification]} = Notification.create_notifications(activity) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/notifications") - - expected_response = - ~s(hi @#{user.nickname}) - - assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) - assert response == expected_response - end - - test "getting a single notification", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - - {:ok, [notification]} = Notification.create_notifications(activity) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/notifications/#{notification.id}") - - expected_response = - ~s(hi @#{user.nickname}) - - assert %{"status" => %{"content" => response}} = json_response(conn, 200) - assert response == expected_response - end - - test "dismissing a single notification", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - - {:ok, [notification]} = Notification.create_notifications(activity) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/notifications/dismiss", %{"id" => notification.id}) - - assert %{} = json_response(conn, 200) - end - - test "clearing all notifications", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - - {:ok, [_notification]} = Notification.create_notifications(activity) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/notifications/clear") - - assert %{} = json_response(conn, 200) - - conn = - build_conn() - |> assign(:user, user) - |> get("/api/v1/notifications") - - assert all = json_response(conn, 200) - assert all == [] - end - - test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - - notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string() - notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string() - notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string() - notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string() - - conn = - conn - |> assign(:user, user) - - # min_id - conn_res = - conn - |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - - # since_id - conn_res = - conn - |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - - # max_id - conn_res = - conn - |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - end - - test "filters notifications using exclude_types", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"}) - {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"}) - {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user) - {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) - {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) - - mention_notification_id = - Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string() - - favorite_notification_id = - Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string() - - reblog_notification_id = - Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string() - - follow_notification_id = - Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string() - - conn = - conn - |> assign(:user, user) - - conn_res = - get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]}) - - assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200) - - conn_res = - get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]}) - - assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200) - - conn_res = - get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]}) - - assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200) - - conn_res = - get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]}) - - assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200) - end - - test "destroy multiple", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) - {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) - - notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string() - notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string() - notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string() - notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string() - - conn = - conn - |> assign(:user, user) - - conn_res = - conn - |> get("/api/v1/notifications") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result - - conn2 = - conn - |> assign(:user, other_user) - - conn_res = - conn2 - |> get("/api/v1/notifications") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - - conn_destroy = - conn - |> delete("/api/v1/notifications/destroy_multiple", %{ - "ids" => [notification1_id, notification2_id] - }) - - assert json_response(conn_destroy, 200) == %{} - - conn_res = - conn2 - |> get("/api/v1/notifications") - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - end - - test "doesn't see notifications after muting user with notifications", %{conn: conn} do - user = insert(:user) - user2 = insert(:user) - - {:ok, _, _, _} = CommonAPI.follow(user, user2) - {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) - - conn = assign(conn, :user, user) - - conn = get(conn, "/api/v1/notifications") - - assert length(json_response(conn, 200)) == 1 - - {:ok, user} = User.mute(user, user2) - - conn = assign(build_conn(), :user, user) - conn = get(conn, "/api/v1/notifications") - - assert json_response(conn, 200) == [] - end - - test "see notifications after muting user without notifications", %{conn: conn} do - user = insert(:user) - user2 = insert(:user) - - {:ok, _, _, _} = CommonAPI.follow(user, user2) - {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) - - conn = assign(conn, :user, user) - - conn = get(conn, "/api/v1/notifications") - - assert length(json_response(conn, 200)) == 1 - - {:ok, user} = User.mute(user, user2, false) - - conn = assign(build_conn(), :user, user) - conn = get(conn, "/api/v1/notifications") - - assert length(json_response(conn, 200)) == 1 - end - - test "see notifications after muting user with notifications and with_muted parameter", %{ - conn: conn - } do - user = insert(:user) - user2 = insert(:user) - - {:ok, _, _, _} = CommonAPI.follow(user, user2) - {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) - - conn = assign(conn, :user, user) - - conn = get(conn, "/api/v1/notifications") - - assert length(json_response(conn, 200)) == 1 - - {:ok, user} = User.mute(user, user2) - - conn = assign(build_conn(), :user, user) - conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"}) - - assert length(json_response(conn, 200)) == 1 - end - end - describe "reblogging" do test "reblogs and returns the reblogged status", %{conn: conn} do activity = insert(:note_activity) From 209395c7e60afe7115f22afd6936d9c6bdd7bb72 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 24 Sep 2019 19:50:07 +0700 Subject: [PATCH 206/272] Add User.change_info/2 and User.update_info/2 --- lib/mix/tasks/pleroma/user.ex | 25 +-- lib/pleroma/user.ex | 173 +++++------------- lib/pleroma/user/info.ex | 24 +-- .../web/admin_api/admin_api_controller.ex | 59 +++--- lib/pleroma/web/common_api/common_api.ex | 28 +-- .../controllers/mastodon_api_controller.ex | 68 +++---- .../web/twitter_api/twitter_api_controller.ex | 8 +- test/tasks/database_test.exs | 4 +- test/user_test.exs | 18 ++ .../mastodon_api_controller_test.exs | 17 +- test/web/oauth/oauth_controller_test.exs | 9 +- test/web/ostatus/ostatus_controller_test.exs | 20 +- 12 files changed, 146 insertions(+), 307 deletions(-) diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 84c923901..d93ba8dee 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -4,7 +4,6 @@ defmodule Mix.Tasks.Pleroma.User do use Mix.Task - import Ecto.Changeset import Mix.Pleroma alias Pleroma.User alias Pleroma.UserInviteToken @@ -443,39 +442,21 @@ def run(["sign_out", nickname]) do end defp set_moderator(user, value) do - info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value}) - - user_cng = - Ecto.Changeset.change(user) - |> put_embed(:info, info_cng) - - {:ok, user} = User.update_and_set_cache(user_cng) + {:ok, user} = User.update_info(user, &User.Info.admin_api_update(&1, %{is_moderator: value})) shell_info("Moderator status of #{user.nickname}: #{user.info.is_moderator}") user end defp set_admin(user, value) do - info_cng = User.Info.admin_api_update(user.info, %{is_admin: value}) - - user_cng = - Ecto.Changeset.change(user) - |> put_embed(:info, info_cng) - - {:ok, user} = User.update_and_set_cache(user_cng) + {:ok, user} = User.update_info(user, &User.Info.admin_api_update(&1, %{is_admin: value})) shell_info("Admin status of #{user.nickname}: #{user.info.is_admin}") user end defp set_locked(user, value) do - info_cng = User.Info.user_upgrade(user.info, %{locked: value}) - - user_cng = - Ecto.Changeset.change(user) - |> put_embed(:info, info_cng) - - {:ok, user} = User.update_and_set_cache(user_cng) + {:ok, user} = User.update_info(user, &User.Info.user_upgrade(&1, %{locked: value})) shell_info("Locked status of #{user.nickname}: #{user.info.locked}") user diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 8d126933b..422bc6fa6 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -197,8 +197,6 @@ def remote_user_creation(params) do |> truncate_if_exists(:name, name_limit) |> truncate_if_exists(:bio, bio_limit) - info_cng = User.Info.remote_user_creation(%User.Info{}, params[:info]) - changes = %User{} |> cast(params, [:bio, :name, :ap_id, :nickname, :avatar]) @@ -208,7 +206,7 @@ def remote_user_creation(params) do |> validate_length(:bio, max: bio_limit) |> validate_length(:name, max: name_limit) |> put_change(:local, false) - |> put_embed(:info, info_cng) + |> change_info(&User.Info.remote_user_creation(&1, params[:info])) if changes.valid? do case info_cng.changes[:source_data] do @@ -245,7 +243,6 @@ def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) params = Map.put(params, :last_refreshed_at, NaiveDateTime.utc_now()) - info_cng = User.Info.user_upgrade(struct.info, params[:info], remote?) struct |> cast(params, [ @@ -260,7 +257,7 @@ def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do |> validate_format(:nickname, local_nickname_regex()) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, max: name_limit) - |> put_embed(:info, info_cng) + |> change_info(&User.Info.user_upgrade(&1, params[:info], remote?)) end def password_update_changeset(struct, params) do @@ -785,21 +782,15 @@ def decrease_note_count(%User{} = user) do end def update_note_count(%User{} = user) do - note_count_query = + note_count = from( a in Object, where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data), select: count(a.id) ) + |> Repo.one() - note_count = Repo.one(note_count_query) - - info_cng = User.Info.set_note_count(user.info, note_count) - - user - |> change() - |> put_embed(:info, info_cng) - |> update_and_set_cache() + update_info(user, &User.Info.set_note_count(&1, note_count)) end @spec maybe_fetch_follow_information(User.t()) :: User.t() @@ -816,17 +807,7 @@ def maybe_fetch_follow_information(user) do def fetch_follow_information(user) do with {:ok, info} <- ActivityPub.fetch_follow_information_for_user(user) do - info_cng = User.Info.follow_information_update(user.info, info) - - changeset = - user - |> change() - |> put_embed(:info, info_cng) - - update_and_set_cache(changeset) - else - {:error, _} = e -> e - e -> {:error, e} + update_info(user, &User.Info.follow_information_update(&1, info)) end end @@ -900,31 +881,11 @@ def get_recipients_from_activity(%Activity{recipients: to}) do @spec mute(User.t(), User.t(), boolean()) :: {:ok, User.t()} | {:error, String.t()} def mute(muter, %User{ap_id: ap_id}, notifications? \\ true) do - info = muter.info - - info_cng = - User.Info.add_to_mutes(info, ap_id) - |> User.Info.add_to_muted_notifications(info, ap_id, notifications?) - - cng = - change(muter) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + update_info(muter, &User.Info.add_to_mutes(&1, ap_id, notifications?)) end def unmute(muter, %{ap_id: ap_id}) do - info = muter.info - - info_cng = - User.Info.remove_from_mutes(info, ap_id) - |> User.Info.remove_from_muted_notifications(info, ap_id) - - cng = - change(muter) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + update_info(muter, &User.Info.remove_from_mutes(&1, ap_id)) end def subscribe(subscriber, %{ap_id: ap_id}) do @@ -936,26 +897,14 @@ def subscribe(subscriber, %{ap_id: ap_id}) do if blocked do {:error, "Could not subscribe: #{subscribed.nickname} is blocking you"} else - info_cng = - subscribed.info - |> User.Info.add_to_subscribers(subscriber.ap_id) - - change(subscribed) - |> put_embed(:info, info_cng) - |> update_and_set_cache() + update_info(subscribed, &User.Info.add_to_subscribers(&1, subscriber.ap_id)) end end end def unsubscribe(unsubscriber, %{ap_id: ap_id}) do with %User{} = user <- get_cached_by_ap_id(ap_id) do - info_cng = - user.info - |> User.Info.remove_from_subscribers(unsubscriber.ap_id) - - change(user) - |> put_embed(:info, info_cng) - |> update_and_set_cache() + update_info(user, &User.Info.remove_from_subscribers(&1, unsubscriber.ap_id)) end end @@ -990,15 +939,7 @@ def block(blocker, %User{ap_id: ap_id} = blocked) do {:ok, blocker} = update_follower_count(blocker) - info_cng = - blocker.info - |> User.Info.add_to_block(ap_id) - - cng = - change(blocker) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + update_info(blocker, &User.Info.add_to_block(&1, ap_id)) end # helper to handle the block given only an actor's AP id @@ -1007,15 +948,7 @@ def block(blocker, %{ap_id: ap_id}) do end def unblock(blocker, %{ap_id: ap_id}) do - info_cng = - blocker.info - |> User.Info.remove_from_block(ap_id) - - cng = - change(blocker) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + update_info(blocker, &User.Info.remove_from_block(&1, ap_id)) end def mutes?(nil, _), do: false @@ -1072,27 +1005,11 @@ def subscribers(user) do end def block_domain(user, domain) do - info_cng = - user.info - |> User.Info.add_to_domain_block(domain) - - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + update_info(user, &User.Info.add_to_domain_block(&1, domain)) end def unblock_domain(user, domain) do - info_cng = - user.info - |> User.Info.remove_from_domain_block(domain) - - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + update_info(user, &User.Info.remove_from_domain_block(&1, domain)) end def deactivate_async(user, status \\ true) do @@ -1100,13 +1017,7 @@ def deactivate_async(user, status \\ true) do end def deactivate(%User{} = user, status \\ true) do - info_cng = User.Info.set_activation_status(user.info, status) - - with {:ok, user} <- - user - |> change() - |> put_embed(:info, info_cng) - |> update_and_set_cache() do + with {:ok, user} <- update_info(user, &User.Info.set_activation_status(&1, status)) do Enum.each(get_followers(user), &invalidate_cache/1) Enum.each(get_friends(user), &update_follower_count/1) @@ -1115,11 +1026,7 @@ def deactivate(%User{} = user, status \\ true) do end def update_notification_settings(%User{} = user, settings \\ %{}) do - info_changeset = User.Info.update_notification_settings(user.info, settings) - - change(user) - |> put_embed(:info, info_changeset) - |> update_and_set_cache() + update_info(user, &User.Info.update_notification_settings(&1, settings)) end def delete(%User{} = user) do @@ -1560,11 +1467,7 @@ def list_inactive_users_query(inactivity_threshold \\ 7) do @spec switch_email_notifications(t(), String.t(), boolean()) :: {:ok, t()} | {:error, Ecto.Changeset.t()} def switch_email_notifications(user, type, status) do - info = Pleroma.User.Info.update_email_notifications(user.info, %{type => status}) - - change(user) - |> put_embed(:info, info) - |> update_and_set_cache() + update_info(user, &User.Info.update_email_notifications(&1, %{type => status})) end @doc """ @@ -1586,13 +1489,8 @@ def touch_last_digest_emailed_at(user) do def toggle_confirmation(%User{} = user) do need_confirmation? = !user.info.confirmation_pending - info_changeset = - User.Info.confirmation_changeset(user.info, need_confirmation: need_confirmation?) - user - |> change() - |> put_embed(:info, info_changeset) - |> update_and_set_cache() + |> update_info(&User.Info.confirmation_changeset(&1, need_confirmation: need_confirmation?)) end def get_mascot(%{info: %{mascot: %{} = mascot}}) when not is_nil(mascot) do @@ -1615,16 +1513,11 @@ def get_mascot(%{info: %{mascot: mascot}}) when is_nil(mascot) do } end - def ensure_keys_present(%User{info: info} = user) do - if info.keys do - {:ok, user} - else - {:ok, pem} = Keys.generate_rsa_pem() + def ensure_keys_present(%{info: %{keys: keys}} = user) when not is_nil(keys), do: {:ok, user} - user - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:info, User.Info.set_keys(info, pem)) - |> update_and_set_cache() + def ensure_keys_present(%User{} = user) do + with {:ok, pem} <- Keys.generate_rsa_pem() do + update_info(user, &User.Info.set_keys(&1, pem)) end end @@ -1670,4 +1563,26 @@ def change_email(user, email) do |> validate_format(:email, @email_regex) |> update_and_set_cache() end + + @doc """ + Changes `user.info` and returns the user changeset. + + `fun` is called with the `user.info`. + """ + def change_info(user, fun) do + changeset = change(user) + info = get_field(changeset, :info) || %User.Info{} + put_embed(changeset, :info, fun.(info)) + end + + @doc """ + Updates `user.info` and sets cache. + + `fun` is called with the `user.info`. + """ + def update_info(user, fun) do + user + |> change_info(fun) + |> update_and_set_cache() + end end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 99745f496..92e3944f7 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -187,16 +187,11 @@ def set_subscribers(info, subscribers) do |> validate_required([:subscribers]) end - @spec add_to_mutes(Info.t(), String.t()) :: Changeset.t() - def add_to_mutes(info, muted) do - set_mutes(info, Enum.uniq([muted | info.mutes])) - end - - @spec add_to_muted_notifications(Changeset.t(), Info.t(), String.t(), boolean()) :: - Changeset.t() - def add_to_muted_notifications(changeset, info, muted, notifications?) do - set_notification_mutes( - changeset, + @spec add_to_mutes(Info.t(), String.t(), boolean()) :: Changeset.t() + def add_to_mutes(info, muted, notifications?) do + info + |> set_mutes(Enum.uniq([muted | info.mutes])) + |> set_notification_mutes( Enum.uniq([muted | info.muted_notifications]), notifications? ) @@ -204,12 +199,9 @@ def add_to_muted_notifications(changeset, info, muted, notifications?) do @spec remove_from_mutes(Info.t(), String.t()) :: Changeset.t() def remove_from_mutes(info, muted) do - set_mutes(info, List.delete(info.mutes, muted)) - end - - @spec remove_from_muted_notifications(Changeset.t(), Info.t(), String.t()) :: Changeset.t() - def remove_from_muted_notifications(changeset, info, muted) do - set_notification_mutes(changeset, List.delete(info.muted_notifications, muted), true) + info + |> set_mutes(List.delete(info.mutes, muted)) + |> set_notification_mutes(List.delete(info.muted_notifications, muted), true) end def add_to_block(info, blocked) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 0d1db8fa0..6e703d169 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -254,18 +254,12 @@ def right_add(%{assigns: %{user: admin}} = conn, %{ "nickname" => nickname }) when permission_group in ["moderator", "admin"] do - user = User.get_cached_by_nickname(nickname) + info = Map.put(%{}, "is_" <> permission_group, true) - info = - %{} - |> Map.put("is_" <> permission_group, true) - - info_cng = User.Info.admin_api_update(user.info, info) - - cng = - user - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:info, info_cng) + {:ok, user} = + nickname + |> User.get_cached_by_nickname() + |> User.update_info(&User.Info.admin_api_update(&1, info)) ModerationLog.insert_log(%{ action: "grant", @@ -274,8 +268,6 @@ def right_add(%{assigns: %{user: admin}} = conn, %{ permission: permission_group }) - {:ok, _user} = User.update_and_set_cache(cng) - json(conn, info) end @@ -293,40 +285,33 @@ def right_get(conn, %{"nickname" => nickname}) do }) end + def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do + render_error(conn, :forbidden, "You can't revoke your own admin status.") + end + def right_delete( - %{assigns: %{user: %User{:nickname => admin_nickname} = admin}} = conn, + %{assigns: %{user: admin}} = conn, %{ "permission_group" => permission_group, "nickname" => nickname } ) when permission_group in ["moderator", "admin"] do - if admin_nickname == nickname do - render_error(conn, :forbidden, "You can't revoke your own admin status.") - else - user = User.get_cached_by_nickname(nickname) + info = Map.put(%{}, "is_" <> permission_group, false) - info = - %{} - |> Map.put("is_" <> permission_group, false) + {:ok, user} = + nickname + |> User.get_cached_by_nickname() + |> User.update_info(&User.Info.admin_api_update(&1, info)) - info_cng = User.Info.admin_api_update(user.info, info) + ModerationLog.insert_log(%{ + action: "revoke", + actor: admin, + subject: user, + permission: permission_group + }) - cng = - Ecto.Changeset.change(user) - |> Ecto.Changeset.put_embed(:info, info_cng) - - {:ok, _user} = User.update_and_set_cache(cng) - - ModerationLog.insert_log(%{ - action: "revoke", - actor: admin, - subject: user, - permission: permission_group - }) - - json(conn, info) - end + json(conn, info) end def right_delete(conn, _) do diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 5faddc9f4..2f12ad43a 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -302,12 +302,11 @@ def post(user, %{"status" => status} = data) do # Updates the emojis for a user based on their profile def update(user) do + emoji = emoji_from_profile(user) + source_data = user.info |> Map.get(:source_data, {}) |> Map.put("tag", emoji) + user = - with emoji <- emoji_from_profile(user), - source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji), - info_cng <- User.Info.set_source_data(user.info, source_data), - change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), - {:ok, user} <- User.update_and_set_cache(change) do + with {:ok, user} <- User.update_info(user, &User.Info.set_source_data(&1, source_data)) do user else _e -> @@ -336,10 +335,7 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do } } = activity <- get_by_id_or_ap_id(id_or_ap_id), true <- Visibility.is_public?(activity), - %{valid?: true} = info_changeset <- User.Info.add_pinnned_activity(user.info, activity), - changeset <- - Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset), - {:ok, _user} <- User.update_and_set_cache(changeset) do + {:ok, _user} <- User.update_info(user, &User.Info.add_pinnned_activity(&1, activity)) do {:ok, activity} else %{errors: [pinned_activities: {err, _}]} -> @@ -352,11 +348,7 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do def unpin(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), - %{valid?: true} = info_changeset <- - User.Info.remove_pinnned_activity(user.info, activity), - changeset <- - Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset), - {:ok, _user} <- User.update_and_set_cache(changeset) do + {:ok, _user} <- User.update_info(user, &User.Info.remove_pinnned_activity(&1, activity)) do {:ok, activity} else %{errors: [pinned_activities: {err, _}]} -> @@ -462,9 +454,7 @@ def hide_reblogs(user, muted) do ap_id = muted.ap_id if ap_id not in user.info.muted_reblogs do - info_changeset = User.Info.add_reblog_mute(user.info, ap_id) - changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset) - User.update_and_set_cache(changeset) + User.update_info(user, &User.Info.add_reblog_mute(&1, ap_id)) end end @@ -472,9 +462,7 @@ def show_reblogs(user, muted) do ap_id = muted.ap_id if ap_id in user.info.muted_reblogs do - info_changeset = User.Info.remove_reblog_mute(user.info, ap_id) - changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset) - User.update_and_set_cache(changeset) + User.update_info(user, &User.Info.remove_reblog_mute(&1, ap_id)) end end end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 270c74089..8a5287079 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -188,14 +188,13 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do end) |> Map.put(:emoji, user_info_emojis) - info_cng = User.Info.profile_update(user.info, info_params) + changeset = + user + |> User.update_changeset(user_params) + |> User.change_info(&User.Info.profile_update(&1, info_params)) - with changeset <- User.update_changeset(user, user_params), - changeset <- Changeset.put_embed(changeset, :info, info_cng), - {:ok, user} <- User.update_and_set_cache(changeset) do - if original_user != user do - CommonAPI.update(user) - end + with {:ok, user} <- User.update_and_set_cache(changeset) do + if original_user != user, do: CommonAPI.update(user) json( conn, @@ -225,12 +224,10 @@ def update_avatar(%{assigns: %{user: user}} = conn, params) do end def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do - with new_info <- %{"banner" => %{}}, - info_cng <- User.Info.profile_update(user.info, new_info), - changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng), - {:ok, user} <- User.update_and_set_cache(changeset) do - CommonAPI.update(user) + new_info = %{"banner" => %{}} + with {:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do + CommonAPI.update(user) json(conn, %{url: nil}) end end @@ -238,9 +235,7 @@ def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do def update_banner(%{assigns: %{user: user}} = conn, params) do with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner), new_info <- %{"banner" => object.data}, - info_cng <- User.Info.profile_update(user.info, new_info), - changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng), - {:ok, user} <- User.update_and_set_cache(changeset) do + {:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do CommonAPI.update(user) %{"url" => [%{"href" => href} | _]} = object.data @@ -249,10 +244,9 @@ def update_banner(%{assigns: %{user: user}} = conn, params) do end def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do - with new_info <- %{"background" => %{}}, - info_cng <- User.Info.profile_update(user.info, new_info), - changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng), - {:ok, _user} <- User.update_and_set_cache(changeset) do + new_info = %{"background" => %{}} + + with {:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do json(conn, %{url: nil}) end end @@ -260,9 +254,7 @@ def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do def update_background(%{assigns: %{user: user}} = conn, params) do with {:ok, object} <- ActivityPub.upload(params, type: :background), new_info <- %{"background" => object.data}, - info_cng <- User.Info.profile_update(user.info, new_info), - changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng), - {:ok, _user} <- User.update_and_set_cache(changeset) do + {:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do %{"url" => [%{"href" => href} | _]} = object.data json(conn, %{url: href}) @@ -816,26 +808,16 @@ def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do def set_mascot(%{assigns: %{user: user}} = conn, %{"file" => file}) do with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), %{} = attachment_data <- Map.put(object.data, "id", object.id), - %{type: type} = rendered <- + # Reject if not an image + %{type: "image"} = rendered <- StatusView.render("attachment.json", %{attachment: attachment_data}) do - # Reject if not an image - if type == "image" do - # Sure! - # Save to the user's info - info_changeset = User.Info.mascot_update(user.info, rendered) + # Sure! + # Save to the user's info + {:ok, _user} = User.update_info(user, &User.Info.mascot_update(&1, rendered)) - user_changeset = - user - |> Changeset.change() - |> Changeset.put_embed(:info, info_changeset) - - {:ok, _user} = User.update_and_set_cache(user_changeset) - - conn - |> json(rendered) - else - render_error(conn, :unsupported_media_type, "mascots can only be images") - end + json(conn, rendered) + else + %{type: _} -> render_error(conn, :unsupported_media_type, "mascots can only be images") end end @@ -1366,11 +1348,7 @@ def index(%{assigns: %{user: user}} = conn, _params) do end def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do - info_cng = User.Info.mastodon_settings_update(user.info, settings) - - with changeset <- Changeset.change(user), - changeset <- Changeset.put_embed(changeset, :info, info_cng), - {:ok, _user} <- User.update_and_set_cache(changeset) do + with {:ok, _user} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do json(conn, %{}) else e -> diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 42234ae09..27f3664e0 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -5,7 +5,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do use Pleroma.Web, :controller - alias Ecto.Changeset alias Pleroma.Notification alias Pleroma.User alias Pleroma.Web.OAuth.Token @@ -16,15 +15,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do action_fallback(:errors) def confirm_email(conn, %{"user_id" => uid, "token" => token}) do - with %User{} = user <- User.get_cached_by_id(uid), true <- user.local, true <- user.info.confirmation_pending, true <- user.info.confirmation_token == token, - info_change <- User.Info.confirmation_changeset(user.info, need_confirmation: false), - changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_change), - {:ok, _} <- User.update_and_set_cache(changeset) do conn |> redirect(to: "/") + with %User{info: info} = user <- User.get_cached_by_id(uid), + {:ok, _} <- + User.update_info(user, &User.Info.confirmation_changeset(&1, need_confirmation: false)) do end end diff --git a/test/tasks/database_test.exs b/test/tasks/database_test.exs index a9925c361..b63dcac00 100644 --- a/test/tasks/database_test.exs +++ b/test/tasks/database_test.exs @@ -77,12 +77,10 @@ test "following and followers count are updated" do assert length(following) == 2 assert info.follower_count == 0 - info_cng = Ecto.Changeset.change(info, %{follower_count: 3}) - {:ok, user} = user |> Ecto.Changeset.change(%{following: following ++ following}) - |> Ecto.Changeset.put_embed(:info, info_cng) + |> User.change_info(&Ecto.Changeset.change(&1, %{follower_count: 3})) |> Repo.update() assert length(user.following) == 4 diff --git a/test/user_test.exs b/test/user_test.exs index 21ea1d28e..126bd69e8 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1707,4 +1707,22 @@ test "sets password_reset_pending to true", %{user: user} do assert password_reset_pending end end + + test "change_info/2" do + user = insert(:user) + assert user.info.hide_follows == false + + changeset = User.change_info(user, &User.Info.profile_update(&1, %{hide_follows: true})) + assert changeset.changes.info.changes.hide_follows == true + end + + test "update_info/2" do + user = insert(:user) + assert user.info.hide_follows == false + + assert {:ok, _} = User.update_info(user, &User.Info.profile_update(&1, %{hide_follows: true})) + + assert %{info: %{hide_follows: true}} = Repo.get(User, user.id) + assert {:ok, %{info: %{hide_follows: true}}} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") + end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 73a3bf135..e32468f85 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2613,14 +2613,11 @@ test "get instance stats", %{conn: conn} do {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"}) # Stats should count users with missing or nil `info.deactivated` value - user = User.get_cached_by_id(user.id) - info_change = Changeset.change(user.info, %{deactivated: nil}) {:ok, _user} = - user - |> Changeset.change() - |> Changeset.put_embed(:info, info_change) - |> User.update_and_set_cache() + user.id + |> User.get_cached_by_id() + |> User.update_info(&Changeset.change(&1, %{deactivated: nil})) Pleroma.Stats.force_update() @@ -3953,13 +3950,9 @@ test "it returns 400 when user is not local", %{conn: conn, user: user} do describe "POST /api/v1/pleroma/accounts/confirmation_resend" do setup do - user = insert(:user) - info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true) - {:ok, user} = - user - |> Changeset.change() - |> Changeset.put_embed(:info, info_change) + insert(:user) + |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true)) |> Repo.update() assert user.info.confirmation_pending diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index 8b88fd784..0cf755806 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do import Pleroma.Factory alias Pleroma.Repo + alias Pleroma.User alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.OAuthController alias Pleroma.Web.OAuth.Token @@ -775,15 +776,11 @@ test "rejects token exchange with invalid client credentials" do test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do Pleroma.Config.put([:instance, :account_activation_required], true) - password = "testpassword" - user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) - info_change = Pleroma.User.Info.confirmation_changeset(user.info, need_confirmation: true) {:ok, user} = - user - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:info, info_change) + insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) + |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true)) |> Repo.update() refute Pleroma.User.auth_active?(user) diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index ec96f0012..2b40fb47e 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -50,20 +50,16 @@ test "decodes a salmon with a changed magic key", %{conn: conn} do assert response(conn, 200) end) =~ "[error]" - # Set a wrong magic-key for a user so it has to refetch - salmon_user = User.get_cached_by_ap_id("http://gs.example.org:4040/index.php/user/1") - # Wrong key - info_cng = - User.Info.remote_user_creation(salmon_user.info, %{ - magic_key: - "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" - }) + info = %{ + magic_key: + "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" + } - salmon_user - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:info, info_cng) - |> User.update_and_set_cache() + # Set a wrong magic-key for a user so it has to refetch + "http://gs.example.org:4040/index.php/user/1" + |> User.get_cached_by_ap_id() + |> User.update_info(&User.Info.remote_user_creation(&1, info)) assert capture_log(fn -> conn = From 1bea67cb5e70ae28209a193c33b9da2d3c41cfb7 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 24 Sep 2019 14:14:34 +0700 Subject: [PATCH 207/272] Cleanup Pleroma.User --- lib/pleroma/user.ex | 231 ++++++++---------- lib/pleroma/web/common_api/common_api.ex | 25 +- .../web/twitter_api/twitter_api_controller.ex | 7 +- 3 files changed, 108 insertions(+), 155 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 422bc6fa6..640ef05c4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -106,9 +106,7 @@ def profile_url(%User{info: %{source_data: %{"url" => url}}}), do: url def profile_url(%User{ap_id: ap_id}), do: ap_id def profile_url(_), do: nil - def ap_id(%User{nickname: nickname}) do - "#{Web.base_url()}/users/#{nickname}" - end + def ap_id(%User{nickname: nickname}), do: "#{Web.base_url()}/users/#{nickname}" def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers" @@ -119,12 +117,9 @@ def ap_following(%User{} = user), do: "#{ap_id(user)}/following" def user_info(%User{} = user, args \\ %{}) do following_count = - if args[:following_count], - do: args[:following_count], - else: user.info.following_count || following_count(user) + Map.get(args, :following_count, user.info.following_count || following_count(user)) - follower_count = - if args[:follower_count], do: args[:follower_count], else: user.info.follower_count + follower_count = Map.get(args, :follower_count, user.info.follower_count) %{ note_count: user.info.note_count, @@ -137,12 +132,11 @@ def user_info(%User{} = user, args \\ %{}) do end def follow_state(%User{} = user, %User{} = target) do - follow_activity = Utils.fetch_latest_follow(user, target) - - if follow_activity, - do: follow_activity.data["state"], + case Utils.fetch_latest_follow(user, target) do + %{data: %{"state" => state}} -> state # Ideally this would be nil, but then Cachex does not commit the value - else: false + _ -> false + end end def get_cached_follow_state(user, target) do @@ -152,11 +146,7 @@ def get_cached_follow_state(user, target) do @spec set_follow_state_cache(String.t(), String.t(), String.t()) :: {:ok | :error, boolean()} def set_follow_state_cache(user_ap_id, target_ap_id, state) do - Cachex.put( - :user_cache, - "follow_state:#{user_ap_id}|#{target_ap_id}", - state - ) + Cachex.put(:user_cache, "follow_state:#{user_ap_id}|#{target_ap_id}", state) end def set_info_cache(user, args) do @@ -197,32 +187,25 @@ def remote_user_creation(params) do |> truncate_if_exists(:name, name_limit) |> truncate_if_exists(:bio, bio_limit) - changes = - %User{} + changeset = + %User{local: false} |> cast(params, [:bio, :name, :ap_id, :nickname, :avatar]) |> validate_required([:name, :ap_id]) |> unique_constraint(:nickname) |> validate_format(:nickname, @email_regex) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, max: name_limit) - |> put_change(:local, false) |> change_info(&User.Info.remote_user_creation(&1, params[:info])) - if changes.valid? do - case info_cng.changes[:source_data] do - %{"followers" => followers, "following" => following} -> - changes - |> put_change(:follower_address, followers) - |> put_change(:following_address, following) + case params[:info][:source_data] do + %{"followers" => followers, "following" => following} -> + changeset + |> put_change(:follower_address, followers) + |> put_change(:following_address, following) - _ -> - followers = User.ap_followers(%User{nickname: changes.changes[:nickname]}) - - changes - |> put_change(:follower_address, followers) - end - else - changes + _ -> + followers = ap_followers(%User{nickname: get_field(changeset, :nickname)}) + put_change(changeset, :follower_address, followers) end end @@ -308,43 +291,39 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do opts[:need_confirmation] end - info_change = - User.Info.confirmation_changeset(%User.Info{}, need_confirmation: need_confirmation?) + struct + |> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation]) + |> validate_required([:name, :nickname, :password, :password_confirmation]) + |> validate_confirmation(:password) + |> unique_constraint(:email) + |> unique_constraint(:nickname) + |> validate_exclusion(:nickname, Pleroma.Config.get([User, :restricted_nicknames])) + |> validate_format(:nickname, local_nickname_regex()) + |> validate_format(:email, @email_regex) + |> validate_length(:bio, max: bio_limit) + |> validate_length(:name, min: 1, max: name_limit) + |> change_info(&User.Info.confirmation_changeset(&1, need_confirmation: need_confirmation?)) + |> maybe_validate_required_email(opts[:external]) + |> put_password_hash + |> put_ap_id() + |> unique_constraint(:ap_id) + |> put_following_and_follower_address() + end - changeset = - struct - |> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation]) - |> validate_required([:name, :nickname, :password, :password_confirmation]) - |> validate_confirmation(:password) - |> unique_constraint(:email) - |> unique_constraint(:nickname) - |> validate_exclusion(:nickname, Pleroma.Config.get([User, :restricted_nicknames])) - |> validate_format(:nickname, local_nickname_regex()) - |> validate_format(:email, @email_regex) - |> validate_length(:bio, max: bio_limit) - |> validate_length(:name, min: 1, max: name_limit) - |> put_change(:info, info_change) + def maybe_validate_required_email(changeset, true), do: changeset + def maybe_validate_required_email(changeset, _), do: validate_required(changeset, [:email]) - changeset = - if opts[:external] do - changeset - else - validate_required(changeset, [:email]) - end + defp put_ap_id(changeset) do + ap_id = ap_id(%User{nickname: get_field(changeset, :nickname)}) + put_change(changeset, :ap_id, ap_id) + end - if changeset.valid? do - ap_id = User.ap_id(%User{nickname: changeset.changes[:nickname]}) - followers = User.ap_followers(%User{nickname: changeset.changes[:nickname]}) + defp put_following_and_follower_address(changeset) do + followers = ap_followers(%User{nickname: get_field(changeset, :nickname)}) - changeset - |> put_password_hash - |> put_change(:ap_id, ap_id) - |> unique_constraint(:ap_id) - |> put_change(:following, [followers]) - |> put_change(:follower_address, followers) - else - changeset - end + changeset + |> put_change(:following, [followers]) + |> put_change(:follower_address, followers) end defp autofollow_users(user) do @@ -359,9 +338,8 @@ defp autofollow_users(user) do @doc "Inserts provided changeset, performs post-registration actions (confirmation email sending etc.)" def register(%Ecto.Changeset{} = changeset) do - with {:ok, user} <- Repo.insert(changeset), - {:ok, user} <- post_register_action(user) do - {:ok, user} + with {:ok, user} <- Repo.insert(changeset) do + post_register_action(user) end end @@ -407,7 +385,7 @@ def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) do end def maybe_direct_follow(%User{} = follower, %User{} = followed) do - if not User.ap_enabled?(followed) do + if not ap_enabled?(followed) do follow(follower, followed) else {:ok, follower} @@ -440,9 +418,7 @@ def follow_all(follower, followeds) do {1, [follower]} = Repo.update_all(q, []) - Enum.each(followeds, fn followed -> - update_follower_count(followed) - end) + Enum.each(followeds, &update_follower_count/1) set_cache(follower) end @@ -552,8 +528,6 @@ def set_cache(%User{} = user) do def update_and_set_cache(changeset) do with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do set_cache(user) - else - e -> e end end @@ -590,9 +564,7 @@ def get_cached_by_nickname(nickname) do key = "nickname:#{nickname}" Cachex.fetch!(:user_cache, key, fn -> - user_result = get_or_fetch_by_nickname(nickname) - - case user_result do + case get_or_fetch_by_nickname(nickname) do {:ok, user} -> {:commit, user} {:error, _error} -> {:ignore, nil} end @@ -632,13 +604,11 @@ def get_by_nickname_or_email(nickname_or_email) do def get_cached_user_info(user) do key = "user_info:#{user.id}" - Cachex.fetch!(:user_cache, key, fn _ -> user_info(user) end) + Cachex.fetch!(:user_cache, key, fn -> user_info(user) end) end def fetch_by_nickname(nickname) do - ap_try = ActivityPub.make_user_from_nickname(nickname) - - case ap_try do + case ActivityPub.make_user_from_nickname(nickname) do {:ok, user} -> {:ok, user} _ -> OStatus.make_user(nickname) end @@ -673,7 +643,8 @@ def get_followers_query(%User{} = user, nil) do end def get_followers_query(user, page) do - from(u in get_followers_query(user, nil)) + user + |> get_followers_query(nil) |> User.Query.paginate(page, 20) end @@ -689,18 +660,17 @@ def get_followers(user, page \\ nil) do @spec get_external_followers(User.t(), pos_integer()) :: {:ok, list(User.t())} def get_external_followers(user, page \\ nil) do - q = - user - |> get_followers_query(page) - |> User.Query.build(%{external: true}) - - {:ok, Repo.all(q)} + user + |> get_followers_query(page) + |> User.Query.build(%{external: true}) + |> Repo.all() end def get_followers_ids(user, page \\ nil) do - q = get_followers_query(user, page) - - Repo.all(from(u in q, select: u.id)) + user + |> get_followers_query(page) + |> select([u], u.id) + |> Repo.all() end @spec get_friends_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() @@ -709,7 +679,8 @@ def get_friends_query(%User{} = user, nil) do end def get_friends_query(user, page) do - from(u in get_friends_query(user, nil)) + user + |> get_friends_query(nil) |> User.Query.paginate(page, 20) end @@ -723,9 +694,10 @@ def get_friends(user, page \\ nil) do end def get_friends_ids(user, page \\ nil) do - q = get_friends_query(user, page) - - Repo.all(from(u in q, select: u.id)) + user + |> get_friends_query(page) + |> select([u], u.id) + |> Repo.all() end @spec get_follow_requests(User.t()) :: {:ok, [User.t()]} @@ -889,12 +861,10 @@ def unmute(muter, %{ap_id: ap_id}) do end def subscribe(subscriber, %{ap_id: ap_id}) do - deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) - with %User{} = subscribed <- get_cached_by_ap_id(ap_id) do - blocked = blocks?(subscribed, subscriber) and deny_follow_blocked + deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) - if blocked do + if blocks?(subscribed, subscriber) and deny_follow_blocked do {:error, "Could not subscribe: #{subscribed.nickname} is blocking you"} else update_info(subscribed, &User.Info.add_to_subscribers(&1, subscriber.ap_id)) @@ -933,9 +903,7 @@ def block(blocker, %User{ap_id: ap_id} = blocked) do blocker end - if following?(blocked, blocker) do - unfollow(blocked, blocker) - end + if following?(blocked, blocker), do: unfollow(blocked, blocker) {:ok, blocker} = update_follower_count(blocker) @@ -1168,17 +1136,19 @@ defp delete_activity(%{data: %{"type" => "Create"}} = activity) do end defp delete_activity(%{data: %{"type" => "Like"}} = activity) do - user = get_cached_by_ap_id(activity.actor) object = Object.normalize(activity) - ActivityPub.unlike(user, object) + activity.actor + |> get_cached_by_ap_id() + |> ActivityPub.unlike(object) end defp delete_activity(%{data: %{"type" => "Announce"}} = activity) do - user = get_cached_by_ap_id(activity.actor) object = Object.normalize(activity) - ActivityPub.unannounce(user, object) + activity.actor + |> get_cached_by_ap_id() + |> ActivityPub.unannounce(object) end defp delete_activity(_activity), do: "Doing nothing" @@ -1190,9 +1160,7 @@ def html_filter_policy(%User{info: %{no_rich_text: true}}) do def html_filter_policy(_), do: Pleroma.Config.get([:markup, :scrub_policy]) def fetch_by_ap_id(ap_id) do - ap_try = ActivityPub.make_user_from_ap_id(ap_id) - - case ap_try do + case ActivityPub.make_user_from_ap_id(ap_id) do {:ok, user} -> {:ok, user} @@ -1207,7 +1175,7 @@ def fetch_by_ap_id(ap_id) do def get_or_fetch_by_ap_id(ap_id) do user = get_cached_by_ap_id(ap_id) - if !is_nil(user) and !User.needs_update?(user) do + if !is_nil(user) and !needs_update?(user) do {:ok, user} else # Whether to fetch initial posts for the user (if it's a new user & the fetching is enabled) @@ -1227,19 +1195,20 @@ def get_or_fetch_by_ap_id(ap_id) do @doc "Creates an internal service actor by URI if missing. Optionally takes nickname for addressing." def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do - if user = get_cached_by_ap_id(uri) do + with %User{} = user <- get_cached_by_ap_id(uri) do user else - changes = - %User{info: %User.Info{}} - |> cast(%{}, [:ap_id, :nickname, :local]) - |> put_change(:ap_id, uri) - |> put_change(:nickname, nickname) - |> put_change(:local, true) - |> put_change(:follower_address, uri <> "/followers") + _ -> + {:ok, user} = + %User{info: %User.Info{}} + |> cast(%{}, [:ap_id, :nickname, :local]) + |> put_change(:ap_id, uri) + |> put_change(:nickname, nickname) + |> put_change(:local, true) + |> put_change(:follower_address, uri <> "/followers") + |> Repo.insert() - {:ok, user} = Repo.insert(changes) - user + user end end @@ -1296,23 +1265,21 @@ def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname) # this is because we have synchronous follow APIs and need to simulate them # with an async handshake def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do - with %User{} = a <- User.get_cached_by_id(a.id), - %User{} = b <- User.get_cached_by_id(b.id) do + with %User{} = a <- get_cached_by_id(a.id), + %User{} = b <- get_cached_by_id(b.id) do {:ok, a, b} else - _e -> - :error + nil -> :error end end def wait_and_refresh(timeout, %User{} = a, %User{} = b) do with :ok <- :timer.sleep(timeout), - %User{} = a <- User.get_cached_by_id(a.id), - %User{} = b <- User.get_cached_by_id(b.id) do + %User{} = a <- get_cached_by_id(a.id), + %User{} = b <- get_cached_by_id(b.id) do {:ok, a, b} else - _e -> - :error + nil -> :error end end @@ -1374,7 +1341,7 @@ defp update_tags(%User{} = user, new_tags) do defp normalize_tags(tags) do [tags] |> List.flatten() - |> Enum.map(&String.downcase(&1)) + |> Enum.map(&String.downcase/1) end defp local_nickname_regex do diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 2f12ad43a..40eebe2aa 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -309,8 +309,7 @@ def update(user) do with {:ok, user} <- User.update_info(user, &User.Info.set_source_data(&1, source_data)) do user else - _e -> - user + _e -> user end ActivityPub.update(%{ @@ -338,11 +337,8 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do {:ok, _user} <- User.update_info(user, &User.Info.add_pinnned_activity(&1, activity)) do {:ok, activity} else - %{errors: [pinned_activities: {err, _}]} -> - {:error, err} - - _ -> - {:error, dgettext("errors", "Could not pin")} + {:error, %{changes: %{info: %{errors: [pinned_activities: {err, _}]}}}} -> {:error, err} + _ -> {:error, dgettext("errors", "Could not pin")} end end @@ -351,11 +347,8 @@ def unpin(id_or_ap_id, user) do {:ok, _user} <- User.update_info(user, &User.Info.remove_pinnned_activity(&1, activity)) do {:ok, activity} else - %{errors: [pinned_activities: {err, _}]} -> - {:error, err} - - _ -> - {:error, dgettext("errors", "Could not unpin")} + %{errors: [pinned_activities: {err, _}]} -> {:error, err} + _ -> {:error, dgettext("errors", "Could not unpin")} end end @@ -450,17 +443,13 @@ defp set_visibility(activity, %{"visibility" => visibility}) do defp set_visibility(activity, _), do: {:ok, activity} - def hide_reblogs(user, muted) do - ap_id = muted.ap_id - + def hide_reblogs(user, %{ap_id: ap_id} = _muted) do if ap_id not in user.info.muted_reblogs do User.update_info(user, &User.Info.add_reblog_mute(&1, ap_id)) end end - def show_reblogs(user, muted) do - ap_id = muted.ap_id - + def show_reblogs(user, %{ap_id: ap_id} = _muted) do if ap_id in user.info.muted_reblogs do User.update_info(user, &User.Info.remove_reblog_mute(&1, ap_id)) end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 27f3664e0..aa06e2630 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -15,14 +15,11 @@ defmodule Pleroma.Web.TwitterAPI.Controller do action_fallback(:errors) def confirm_email(conn, %{"user_id" => uid, "token" => token}) do - true <- user.local, - true <- user.info.confirmation_pending, - true <- user.info.confirmation_token == token, - conn - |> redirect(to: "/") with %User{info: info} = user <- User.get_cached_by_id(uid), + true <- user.local and info.confirmation_pending and info.confirmation_token == token, {:ok, _} <- User.update_info(user, &User.Info.confirmation_changeset(&1, need_confirmation: false)) do + redirect(conn, to: "/") end end From 035f22f7849815c5f77a734c56f409c0f08ac853 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 24 Sep 2019 14:49:02 +0700 Subject: [PATCH 208/272] Fix Credo warnings --- .../web/mastodon_api/controllers/mastodon_api_controller.ex | 2 +- lib/pleroma/web/twitter_api/twitter_api_controller.ex | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 8a5287079..873ef20bc 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -1348,7 +1348,7 @@ def index(%{assigns: %{user: user}} = conn, _params) do end def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do - with {:ok, _user} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do + with {:ok, _} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do json(conn, %{}) else e -> diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index aa06e2630..5024ac70d 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -15,10 +15,11 @@ defmodule Pleroma.Web.TwitterAPI.Controller do action_fallback(:errors) def confirm_email(conn, %{"user_id" => uid, "token" => token}) do + new_info = [need_confirmation: false] + with %User{info: info} = user <- User.get_cached_by_id(uid), true <- user.local and info.confirmation_pending and info.confirmation_token == token, - {:ok, _} <- - User.update_info(user, &User.Info.confirmation_changeset(&1, need_confirmation: false)) do + {:ok, _} <- User.update_info(user, &User.Info.confirmation_changeset(&1, new_info)) do redirect(conn, to: "/") end end From 60cbea5bb2e70d6a843d6f595a3c1cfe9cc78d1e Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 25 Sep 2019 01:25:42 +0300 Subject: [PATCH 209/272] Allow activities pagination via limit/offset --- lib/pleroma/pagination.ex | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 17 +++++++++++------ .../web/admin_api/admin_api_controller.ex | 6 +++++- test/web/activity_pub/activity_pub_test.exs | 15 +++++++++++++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex index b55379c4a..9d279fba7 100644 --- a/lib/pleroma/pagination.ex +++ b/lib/pleroma/pagination.ex @@ -64,6 +64,7 @@ def paginate(query, options, :keyset) do def paginate(query, options, :offset) do query + |> restrict(:order, options) |> restrict(:offset, options) |> restrict(:limit, options) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1cf8b6151..bb0a5ca73 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -519,13 +519,13 @@ def fetch_latest_activity_id_for_context(context, opts \\ %{}) do |> Repo.one() end - def fetch_public_activities(opts \\ %{}) do + def fetch_public_activities(opts \\ %{}, pagination \\ :keyset) do opts = Map.drop(opts, ["user"]) [Pleroma.Constants.as_public()] |> fetch_activities_query(opts) |> restrict_unlisted() - |> Pagination.fetch_paginated(opts) + |> Pagination.fetch_paginated(opts, pagination) |> Enum.reverse() end @@ -918,11 +918,11 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> exclude_poll_votes(opts) end - def fetch_activities(recipients, opts \\ %{}) do + def fetch_activities(recipients, opts \\ %{}, pagination \\ :keyset) do list_memberships = Pleroma.List.memberships(opts["user"]) fetch_activities_query(recipients ++ list_memberships, opts) - |> Pagination.fetch_paginated(opts) + |> Pagination.fetch_paginated(opts, pagination) |> Enum.reverse() |> maybe_update_cc(list_memberships, opts["user"]) end @@ -953,10 +953,15 @@ def fetch_activities_bounded_query(query, recipients, recipients_with_public) do ) end - def fetch_activities_bounded(recipients, recipients_with_public, opts \\ %{}) do + def fetch_activities_bounded( + recipients, + recipients_with_public, + opts \\ %{}, + pagination \\ :keyset + ) do fetch_activities_query([], opts) |> fetch_activities_bounded_query(recipients, recipients_with_public) - |> Pagination.fetch_paginated(opts) + |> Pagination.fetch_paginated(opts, pagination) |> Enum.reverse() end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 0d1db8fa0..6761c32b9 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -463,13 +463,17 @@ def force_password_reset(conn, %{"nickname" => nickname}) do end def list_reports(conn, params) do + {page, page_size} = page_params(params) + params = params |> Map.put("type", "Flag") |> Map.put("skip_preload", true) |> Map.put("total", true) + |> Map.put("limit", page_size) + |> Map.put("offset", (page - 1) * page_size) - reports = ActivityPub.fetch_activities([], params) + reports = ActivityPub.fetch_activities([], params, :offset) conn |> put_view(ReportView) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 4100108a5..f28fd6871 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -647,6 +647,21 @@ test "retrieves ids up to max_id" do assert last == last_expected end + test "paginates via offset/limit" do + _first_activities = ActivityBuilder.insert_list(10) + activities = ActivityBuilder.insert_list(10) + _later_activities = ActivityBuilder.insert_list(10) + first_expected = List.first(activities) + + activities = + ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset) + + first = List.first(activities) + + assert length(activities) == 20 + assert first == first_expected + end + test "doesn't return reblogs for users for whom reblogs have been muted" do activity = insert(:note_activity) user = insert(:user) From b5dfe83433e092a007f85ed9c0ffe5a47dbfcccd Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 18 Sep 2019 21:54:31 +0700 Subject: [PATCH 210/272] Replace `Pleroma.FlakeId` with `flake_id` hex package --- lib/pleroma/activity.ex | 2 +- lib/pleroma/activity_expiration.ex | 3 +- lib/pleroma/application.ex | 1 - lib/pleroma/bookmark.ex | 13 +- lib/pleroma/conversation/participation.ex | 4 +- .../participation_recipient_ship.ex | 2 +- lib/pleroma/delivery.ex | 3 +- lib/pleroma/filter.ex | 2 +- lib/pleroma/flake_id.ex | 182 ------------------ lib/pleroma/list.ex | 2 +- lib/pleroma/notification.ex | 4 +- lib/pleroma/password_reset_token.ex | 2 +- lib/pleroma/registration.ex | 4 +- lib/pleroma/scheduled_activity.ex | 2 +- lib/pleroma/thread_mute.ex | 4 +- lib/pleroma/user.ex | 4 +- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/common_api/utils.ex | 2 +- lib/pleroma/web/oauth/authorization.ex | 2 +- lib/pleroma/web/oauth/token.ex | 2 +- lib/pleroma/web/push/subscription.ex | 2 +- .../web/websub/websub_client_subscription.ex | 2 +- mix.exs | 1 + mix.lock | 3 + test/flake_id_test.exs | 47 ----- 25 files changed, 35 insertions(+), 262 deletions(-) delete mode 100644 lib/pleroma/flake_id.ex delete mode 100644 test/flake_id_test.exs diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index ec558168a..2c04a26f9 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Activity do @type t :: %__MODULE__{} @type actor :: String.t() - @primary_key {:id, Pleroma.FlakeId, autogenerate: true} + @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} # https://github.com/tootsuite/mastodon/blob/master/app/models/notification.rb#L19 @mastodon_notification_types %{ diff --git a/lib/pleroma/activity_expiration.ex b/lib/pleroma/activity_expiration.ex index bf57abca4..7ea5c48ca 100644 --- a/lib/pleroma/activity_expiration.ex +++ b/lib/pleroma/activity_expiration.ex @@ -7,7 +7,6 @@ defmodule Pleroma.ActivityExpiration do alias Pleroma.Activity alias Pleroma.ActivityExpiration - alias Pleroma.FlakeId alias Pleroma.Repo import Ecto.Changeset @@ -17,7 +16,7 @@ defmodule Pleroma.ActivityExpiration do @min_activity_lifetime :timer.hours(1) schema "activity_expirations" do - belongs_to(:activity, Activity, type: FlakeId) + belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType) field(:scheduled_at, :naive_datetime) end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index dabce771d..e805cefa0 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -35,7 +35,6 @@ def start(_type, _args) do Pleroma.Config.TransferTask, Pleroma.Emoji, Pleroma.Captcha, - Pleroma.FlakeId, Pleroma.Daemons.ScheduledActivityDaemon, Pleroma.Daemons.ActivityExpirationDaemon ] ++ diff --git a/lib/pleroma/bookmark.ex b/lib/pleroma/bookmark.ex index d976f949c..221a94f34 100644 --- a/lib/pleroma/bookmark.ex +++ b/lib/pleroma/bookmark.ex @@ -10,20 +10,20 @@ defmodule Pleroma.Bookmark do alias Pleroma.Activity alias Pleroma.Bookmark - alias Pleroma.FlakeId alias Pleroma.Repo alias Pleroma.User @type t :: %__MODULE__{} schema "bookmarks" do - belongs_to(:user, User, type: FlakeId) - belongs_to(:activity, Activity, type: FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType) timestamps() end - @spec create(FlakeId.t(), FlakeId.t()) :: {:ok, Bookmark.t()} | {:error, Changeset.t()} + @spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) :: + {:ok, Bookmark.t()} | {:error, Changeset.t()} def create(user_id, activity_id) do attrs = %{ user_id: user_id, @@ -37,7 +37,7 @@ def create(user_id, activity_id) do |> Repo.insert() end - @spec for_user_query(FlakeId.t()) :: Ecto.Query.t() + @spec for_user_query(FlakeId.Ecto.CompatType.t()) :: Ecto.Query.t() def for_user_query(user_id) do Bookmark |> where(user_id: ^user_id) @@ -52,7 +52,8 @@ def get(user_id, activity_id) do |> Repo.one() end - @spec destroy(FlakeId.t(), FlakeId.t()) :: {:ok, Bookmark.t()} | {:error, Changeset.t()} + @spec destroy(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) :: + {:ok, Bookmark.t()} | {:error, Changeset.t()} def destroy(user_id, activity_id) do from(b in Bookmark, where: b.user_id == ^user_id, diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index ea5b9fe17..e946f6de2 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -13,10 +13,10 @@ defmodule Pleroma.Conversation.Participation do import Ecto.Query schema "conversation_participations" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:conversation, Conversation) field(:read, :boolean, default: false) - field(:last_activity_id, Pleroma.FlakeId, virtual: true) + field(:last_activity_id, FlakeId.Ecto.CompatType, virtual: true) has_many(:recipient_ships, RecipientShip) has_many(:recipients, through: [:recipient_ships, :user]) diff --git a/lib/pleroma/conversation/participation_recipient_ship.ex b/lib/pleroma/conversation/participation_recipient_ship.ex index 932cbd04c..e3d158cbc 100644 --- a/lib/pleroma/conversation/participation_recipient_ship.ex +++ b/lib/pleroma/conversation/participation_recipient_ship.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Conversation.Participation.RecipientShip do import Ecto.Changeset schema "conversation_participation_recipient_ships" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:participation, Participation) end diff --git a/lib/pleroma/delivery.ex b/lib/pleroma/delivery.ex index 29a1e5a77..1d586a252 100644 --- a/lib/pleroma/delivery.ex +++ b/lib/pleroma/delivery.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Delivery do use Ecto.Schema alias Pleroma.Delivery - alias Pleroma.FlakeId alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -16,7 +15,7 @@ defmodule Pleroma.Delivery do import Ecto.Query schema "deliveries" do - belongs_to(:user, User, type: FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:object, Object) end diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex index 90457dadf..c87141582 100644 --- a/lib/pleroma/filter.ex +++ b/lib/pleroma/filter.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Filter do alias Pleroma.User schema "filters" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) field(:filter_id, :integer) field(:hide, :boolean, default: false) field(:whole_word, :boolean, default: true) diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex deleted file mode 100644 index 042cf8659..000000000 --- a/lib/pleroma/flake_id.ex +++ /dev/null @@ -1,182 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.FlakeId do - @moduledoc """ - Flake is a decentralized, k-ordered id generation service. - - Adapted from: - - * [flaky](https://github.com/nirvana/flaky), released under the terms of the Truly Free License, - * [Flake](https://github.com/boundary/flake), Copyright 2012, Boundary, Apache License, Version 2.0 - """ - - @type t :: binary - - use Ecto.Type - use GenServer - require Logger - alias __MODULE__ - import Kernel, except: [to_string: 1] - - defstruct node: nil, time: 0, sq: 0 - - @doc "Converts a binary Flake to a String" - def to_string(<<0::integer-size(64), id::integer-size(64)>>) do - Kernel.to_string(id) - end - - def to_string(<<_::integer-size(64), _::integer-size(48), _::integer-size(16)>> = flake) do - encode_base62(flake) - end - - def to_string(s), do: s - - def from_string(int) when is_integer(int) do - from_string(Kernel.to_string(int)) - end - - for i <- [-1, 0] do - def from_string(unquote(i)), do: <<0::integer-size(128)>> - def from_string(unquote(Kernel.to_string(i))), do: <<0::integer-size(128)>> - end - - def from_string(<<_::integer-size(128)>> = flake), do: flake - - def from_string(string) when is_binary(string) and byte_size(string) < 18 do - case Integer.parse(string) do - {id, ""} -> <<0::integer-size(64), id::integer-size(64)>> - _ -> nil - end - end - - def from_string(string) do - string |> decode_base62 |> from_integer - end - - def to_integer(<>), do: integer - - def from_integer(integer) do - <<_time::integer-size(64), _node::integer-size(48), _seq::integer-size(16)>> = - <> - end - - @doc "Generates a Flake" - @spec get :: binary - def get, do: to_string(:gen_server.call(:flake, :get)) - - # checks that ID is is valid FlakeID - # - @spec is_flake_id?(String.t()) :: boolean - def is_flake_id?(id), do: is_flake_id?(String.to_charlist(id), true) - defp is_flake_id?([c | cs], true) when c >= ?0 and c <= ?9, do: is_flake_id?(cs, true) - defp is_flake_id?([c | cs], true) when c >= ?A and c <= ?Z, do: is_flake_id?(cs, true) - defp is_flake_id?([c | cs], true) when c >= ?a and c <= ?z, do: is_flake_id?(cs, true) - defp is_flake_id?([], true), do: true - defp is_flake_id?(_, _), do: false - - # -- Ecto.Type API - @impl Ecto.Type - def type, do: :uuid - - @impl Ecto.Type - def cast(value) do - {:ok, FlakeId.to_string(value)} - end - - @impl Ecto.Type - def load(value) do - {:ok, FlakeId.to_string(value)} - end - - @impl Ecto.Type - def dump(value) do - {:ok, FlakeId.from_string(value)} - end - - def autogenerate, do: get() - - # -- GenServer API - def start_link(_) do - :gen_server.start_link({:local, :flake}, __MODULE__, [], []) - end - - @impl GenServer - def init([]) do - {:ok, %FlakeId{node: worker_id(), time: time()}} - end - - @impl GenServer - def handle_call(:get, _from, state) do - {flake, new_state} = get(time(), state) - {:reply, flake, new_state} - end - - # Matches when the calling time is the same as the state time. Incr. sq - defp get(time, %FlakeId{time: time, node: node, sq: seq}) do - new_state = %FlakeId{time: time, node: node, sq: seq + 1} - {gen_flake(new_state), new_state} - end - - # Matches when the times are different, reset sq - defp get(newtime, %FlakeId{time: time, node: node}) when newtime > time do - new_state = %FlakeId{time: newtime, node: node, sq: 0} - {gen_flake(new_state), new_state} - end - - # Error when clock is running backwards - defp get(newtime, %FlakeId{time: time}) when newtime < time do - {:error, :clock_running_backwards} - end - - defp gen_flake(%FlakeId{time: time, node: node, sq: seq}) do - <> - end - - defp nthchar_base62(n) when n <= 9, do: ?0 + n - defp nthchar_base62(n) when n <= 35, do: ?A + n - 10 - defp nthchar_base62(n), do: ?a + n - 36 - - defp encode_base62(<>) do - integer - |> encode_base62([]) - |> List.to_string() - end - - defp encode_base62(int, acc) when int < 0, do: encode_base62(-int, acc) - defp encode_base62(int, []) when int == 0, do: '0' - defp encode_base62(int, acc) when int == 0, do: acc - - defp encode_base62(int, acc) do - r = rem(int, 62) - id = div(int, 62) - acc = [nthchar_base62(r) | acc] - encode_base62(id, acc) - end - - defp decode_base62(s) do - decode_base62(String.to_charlist(s), 0) - end - - defp decode_base62([c | cs], acc) when c >= ?0 and c <= ?9, - do: decode_base62(cs, 62 * acc + (c - ?0)) - - defp decode_base62([c | cs], acc) when c >= ?A and c <= ?Z, - do: decode_base62(cs, 62 * acc + (c - ?A + 10)) - - defp decode_base62([c | cs], acc) when c >= ?a and c <= ?z, - do: decode_base62(cs, 62 * acc + (c - ?a + 36)) - - defp decode_base62([], acc), do: acc - - defp time do - {mega_seconds, seconds, micro_seconds} = :erlang.timestamp() - 1_000_000_000 * mega_seconds + seconds * 1000 + :erlang.trunc(micro_seconds / 1000) - end - - defp worker_id do - <> = :crypto.strong_rand_bytes(6) - worker - end -end diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex index c572380c2..c5db1cb62 100644 --- a/lib/pleroma/list.ex +++ b/lib/pleroma/list.ex @@ -13,7 +13,7 @@ defmodule Pleroma.List do alias Pleroma.User schema "lists" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) field(:title, :string) field(:following, {:array, :string}, default: []) field(:ap_id, :string) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 8012389ac..d94ae5971 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -22,8 +22,8 @@ defmodule Pleroma.Notification do schema "notifications" do field(:seen, :boolean, default: false) - belongs_to(:user, User, type: Pleroma.FlakeId) - belongs_to(:activity, Activity, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType) timestamps() end diff --git a/lib/pleroma/password_reset_token.ex b/lib/pleroma/password_reset_token.ex index 4a833f6a5..db398b1fc 100644 --- a/lib/pleroma/password_reset_token.ex +++ b/lib/pleroma/password_reset_token.ex @@ -12,7 +12,7 @@ defmodule Pleroma.PasswordResetToken do alias Pleroma.User schema "password_reset_tokens" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) field(:token, :string) field(:used, :boolean, default: false) diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex index 21fd1fc3f..8544461db 100644 --- a/lib/pleroma/registration.ex +++ b/lib/pleroma/registration.ex @@ -11,10 +11,10 @@ defmodule Pleroma.Registration do alias Pleroma.Repo alias Pleroma.User - @primary_key {:id, Pleroma.FlakeId, autogenerate: true} + @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} schema "registrations" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) field(:provider, :string) field(:uid, :string) field(:info, :map, default: %{}) diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex index de0e54699..fea2cf3ff 100644 --- a/lib/pleroma/scheduled_activity.ex +++ b/lib/pleroma/scheduled_activity.ex @@ -17,7 +17,7 @@ defmodule Pleroma.ScheduledActivity do @min_offset :timer.minutes(5) schema "scheduled_activities" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) field(:scheduled_at, :naive_datetime) field(:params, :map) diff --git a/lib/pleroma/thread_mute.ex b/lib/pleroma/thread_mute.ex index 10d31679d..65cbbede3 100644 --- a/lib/pleroma/thread_mute.ex +++ b/lib/pleroma/thread_mute.ex @@ -12,7 +12,7 @@ defmodule Pleroma.ThreadMute do require Ecto.Query schema "thread_mutes" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) field(:context, :string) end @@ -24,7 +24,7 @@ def changeset(mute, params \\ %{}) do end def query(user_id, context) do - user_id = Pleroma.FlakeId.from_string(user_id) + {:ok, user_id} = FlakeId.Ecto.CompatType.dump(user_id) ThreadMute |> Ecto.Query.where(user_id: ^user_id) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fb1f24254..b168d50a9 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -34,7 +34,7 @@ defmodule Pleroma.User do @type t :: %__MODULE__{} - @primary_key {:id, Pleroma.FlakeId, autogenerate: true} + @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength @email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ @@ -591,7 +591,7 @@ def get_cached_by_nickname_or_id(nickname_or_id, opts \\ []) do restrict_to_local = Pleroma.Config.get([:instance, :limit_to_local_content]) cond do - is_integer(nickname_or_id) or Pleroma.FlakeId.is_flake_id?(nickname_or_id) -> + is_integer(nickname_or_id) or FlakeId.flake_id?(nickname_or_id) -> get_cached_by_id(nickname_or_id) || get_cached_by_nickname(nickname_or_id) restrict_to_local == false -> diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e1e90d667..2486df944 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -510,7 +510,7 @@ def fetch_activities_for_context(context, opts \\ %{}) do end @spec fetch_latest_activity_id_for_context(String.t(), keyword() | map()) :: - Pleroma.FlakeId.t() | nil + FlakeId.Ecto.CompatType.t() | nil def fetch_latest_activity_id_for_context(context, opts \\ %{}) do context |> fetch_activities_for_context_query(Map.merge(%{"skip_preload" => true}, opts)) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 6958c7511..633504a4b 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -25,7 +25,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do # This is a hack for twidere. def get_by_id_or_ap_id(id) do activity = - with true <- Pleroma.FlakeId.is_flake_id?(id), + with true <- FlakeId.flake_id?(id), %Activity{} = activity <- Activity.get_by_id_with_object(id) do activity else diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex index d53e20d12..ed42a34f3 100644 --- a/lib/pleroma/web/oauth/authorization.ex +++ b/lib/pleroma/web/oauth/authorization.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.OAuth.Authorization do field(:scopes, {:array, :string}, default: []) field(:valid_until, :naive_datetime_usec) field(:used, :boolean, default: false) - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:app, App) timestamps() diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index 40f131b57..8ea373805 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Web.OAuth.Token do field(:refresh_token, :string) field(:scopes, {:array, :string}, default: []) field(:valid_until, :naive_datetime_usec) - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:app, App) timestamps() diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex index da301fbbc..988fabaeb 100644 --- a/lib/pleroma/web/push/subscription.ex +++ b/lib/pleroma/web/push/subscription.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.Push.Subscription do @type t :: %__MODULE__{} schema "push_subscriptions" do - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:token, Token) field(:endpoint, :string) field(:key_p256dh, :string) diff --git a/lib/pleroma/web/websub/websub_client_subscription.ex b/lib/pleroma/web/websub/websub_client_subscription.ex index 77703c496..23a04b87d 100644 --- a/lib/pleroma/web/websub/websub_client_subscription.ex +++ b/lib/pleroma/web/websub/websub_client_subscription.ex @@ -13,7 +13,7 @@ defmodule Pleroma.Web.Websub.WebsubClientSubscription do field(:state, :string) field(:subscribers, {:array, :string}, default: []) field(:hub, :string) - belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) timestamps() end diff --git a/mix.exs b/mix.exs index 33a27470b..035cfc64b 100644 --- a/mix.exs +++ b/mix.exs @@ -158,6 +158,7 @@ defp deps do {:ex_const, "~> 0.2"}, {:plug_static_index_html, "~> 1.0.0"}, {:excoveralls, "~> 0.11.1", only: :test}, + {:flake_id, "~> 0.1.0"}, {:mox, "~> 0.5", only: :test} ] ++ oauth_deps() end diff --git a/mix.lock b/mix.lock index 24b34c09c..81209eb0f 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,7 @@ %{ "accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm"}, "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "95e8188490e97505c56636c1379ffdf036c1fdde", [ref: "95e8188490e97505c56636c1379ffdf036c1fdde"]}, + "base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm"}, "base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"}, "bbcode": {:hex, :bbcode, "0.1.1", "0023e2c7814119b2e620b7add67182e3f6019f92bfec9a22da7e99821aceba70", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm"}, @@ -17,6 +18,7 @@ "credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "crontab": {:hex, :crontab, "1.1.7", "b9219f0bdc8678b94143655a8f229716c5810c0636a4489f98c0956137e53985", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, + "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm"}, "db_connection": {:hex, :db_connection, "2.1.1", "a51e8a2ee54ef2ae6ec41a668c85787ed40cb8944928c191280fe34c15b76ae5", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, "decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"}, @@ -34,6 +36,7 @@ "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"}, "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]}, "excoveralls": {:hex, :excoveralls, "0.11.1", "dd677fbdd49114fdbdbf445540ec735808250d56b011077798316505064edb2c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"}, "gen_smtp": {:hex, :gen_smtp, "0.14.0", "39846a03522456077c6429b4badfd1d55e5e7d0fdfb65e935b7c5e38549d9202", [:rebar3], [], "hexpm"}, "gen_stage": {:hex, :gen_stage, "0.14.2", "6a2a578a510c5bfca8a45e6b27552f613b41cf584b58210f017088d3d17d0b14", [:mix], [], "hexpm"}, diff --git a/test/flake_id_test.exs b/test/flake_id_test.exs deleted file mode 100644 index 85ed5bbdf..000000000 --- a/test/flake_id_test.exs +++ /dev/null @@ -1,47 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.FlakeIdTest do - use Pleroma.DataCase - import Kernel, except: [to_string: 1] - import Pleroma.FlakeId - - describe "fake flakes (compatibility with older serial integers)" do - test "from_string/1" do - fake_flake = <<0::integer-size(64), 42::integer-size(64)>> - assert from_string("42") == fake_flake - assert from_string(42) == fake_flake - end - - test "zero or -1 is a null flake" do - fake_flake = <<0::integer-size(128)>> - assert from_string("0") == fake_flake - assert from_string("-1") == fake_flake - end - - test "to_string/1" do - fake_flake = <<0::integer-size(64), 42::integer-size(64)>> - assert to_string(fake_flake) == "42" - end - end - - test "ecto type behaviour" do - flake = <<0, 0, 1, 104, 80, 229, 2, 235, 140, 22, 69, 201, 53, 210, 0, 0>> - flake_s = "9eoozpwTul5mjSEDRI" - - assert cast(flake) == {:ok, flake_s} - assert cast(flake_s) == {:ok, flake_s} - - assert load(flake) == {:ok, flake_s} - assert load(flake_s) == {:ok, flake_s} - - assert dump(flake_s) == {:ok, flake} - assert dump(flake) == {:ok, flake} - end - - test "is_flake_id?/1" do - assert is_flake_id?("9eoozpwTul5mjSEDRI") - refute is_flake_id?("http://example.com/activities/3ebbadd1-eb14-4e20-8118-b6f79c0c7b0b") - end -end From 1b2e4a0ae0648c4e2542edecca131b06aa02016c Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 25 Sep 2019 13:13:35 +0300 Subject: [PATCH 211/272] clears `robot.txt` after tests --- test/tasks/instance_test.exs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/tasks/instance_test.exs b/test/tasks/instance_test.exs index 70986374e..a3b0dcb50 100644 --- a/test/tasks/instance_test.exs +++ b/test/tasks/instance_test.exs @@ -7,7 +7,16 @@ defmodule Pleroma.InstanceTest do setup do File.mkdir_p!(tmp_path()) - on_exit(fn -> File.rm_rf(tmp_path()) end) + + on_exit(fn -> + File.rm_rf(tmp_path()) + static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/") + + if File.exists?(static_dir) do + File.rm_rf(Path.join(static_dir, "robots.txt")) + end + end) + :ok end From cdbe7cd37ab8209acc8979ff5a3132b71feda869 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 24 Sep 2019 09:27:34 +0300 Subject: [PATCH 212/272] When listing emoji packs, be sure to create the directory --- .../controllers/emoji_api_controller.ex | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index 370bee9c3..be1f187ec 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -17,7 +17,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do a map of "pack directory name" to pack.json contents. """ def list_packs(conn, _params) do - with {:ok, results} <- File.ls(@emoji_dir_path) do + # Create the directory first if it does not exist. This is probably the first request made + # with the API so it should be sufficient + with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(@emoji_dir_path)}, + {:ls, {:ok, results}} <- {:ls, File.ls(@emoji_dir_path)} do pack_infos = results |> Enum.filter(&has_pack_json?/1) @@ -28,6 +31,19 @@ def list_packs(conn, _params) do |> Enum.into(%{}) json(conn, pack_infos) + else + {:create_dir, {:error, e}} -> + conn + |> put_status(:internal_server_error) + |> json(%{error: "Failed to create the emoji pack directory at #{@emoji_dir_path}: #{e}"}) + + {:ls, {:error, e}} -> + conn + |> put_status(:internal_server_error) + |> json(%{ + error: + "Failed to get the contents of the emoji pack directory at #{@emoji_dir_path}: #{e}" + }) end end From f21dbbc021ff6d1e97695e08b93acc906fc861f6 Mon Sep 17 00:00:00 2001 From: vaartis Date: Tue, 24 Sep 2019 12:11:25 +0000 Subject: [PATCH 213/272] Move emoji_dir_path & cache_seconds_per_file --- .../controllers/emoji_api_controller.ex | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index be1f187ec..e8c4f57a7 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -3,12 +3,12 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do require Logger - @emoji_dir_path Path.join( - Pleroma.Config.get!([:instance, :static_dir]), - "emoji" - ) - - @cache_seconds_per_file Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file]) + def emoji_dir_path() do + Path.join( + Pleroma.Config.get!([:instance, :static_dir]), + "emoji" + ) + end @doc """ Lists the packs available on the instance as JSON. @@ -19,8 +19,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do def list_packs(conn, _params) do # Create the directory first if it does not exist. This is probably the first request made # with the API so it should be sufficient - with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(@emoji_dir_path)}, - {:ls, {:ok, results}} <- {:ls, File.ls(@emoji_dir_path)} do + with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(emoji_dir_path())}, + {:ls, {:ok, results}} <- {:ls, File.ls(emoji_dir_path())} do pack_infos = results |> Enum.filter(&has_pack_json?/1) @@ -35,33 +35,33 @@ def list_packs(conn, _params) do {:create_dir, {:error, e}} -> conn |> put_status(:internal_server_error) - |> json(%{error: "Failed to create the emoji pack directory at #{@emoji_dir_path}: #{e}"}) + |> json(%{error: "Failed to create the emoji pack directory at #{emoji_dir_path()}: #{e}"}) {:ls, {:error, e}} -> conn |> put_status(:internal_server_error) |> json(%{ error: - "Failed to get the contents of the emoji pack directory at #{@emoji_dir_path}: #{e}" + "Failed to get the contents of the emoji pack directory at #{emoji_dir_path()}: #{e}" }) end end defp has_pack_json?(file) do - dir_path = Path.join(@emoji_dir_path, file) + dir_path = Path.join(emoji_dir_path(), file) # Filter to only use the pack.json packs File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.json")) end defp load_pack(pack_name) do - pack_path = Path.join(@emoji_dir_path, pack_name) + pack_path = Path.join(emoji_dir_path(), pack_name) pack_file = Path.join(pack_path, "pack.json") {pack_name, Jason.decode!(File.read!(pack_file))} end defp validate_pack({name, pack}) do - pack_path = Path.join(@emoji_dir_path, name) + pack_path = Path.join(emoji_dir_path(), name) if can_download?(pack, pack_path) do archive_for_sha = make_archive(name, pack, pack_path) @@ -95,7 +95,8 @@ defp create_archive_and_cache(name, pack, pack_dir, md5) do {:ok, {_, zip_result}} = :zip.zip('#{name}.zip', files, [:memory, cwd: to_charlist(pack_dir)]) - cache_ms = :timer.seconds(@cache_seconds_per_file * Enum.count(files)) + cache_seconds_per_file = Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file]) + cache_ms = :timer.seconds(cache_seconds_per_file * Enum.count(files)) Cachex.put!( :emoji_packs_cache, @@ -131,7 +132,7 @@ defp make_archive(name, pack, pack_dir) do to download packs that the instance shares. """ def download_shared(conn, %{"name" => name}) do - pack_dir = Path.join(@emoji_dir_path, name) + pack_dir = Path.join(emoji_dir_path(), name) pack_file = Path.join(pack_dir, "pack.json") with {_, true} <- {:exists?, File.exists?(pack_file)}, @@ -211,7 +212,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = %{body: emoji_archive} <- Tesla.get!(uri), {_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do local_name = data["as"] || name - pack_dir = Path.join(@emoji_dir_path, local_name) + pack_dir = Path.join(emoji_dir_path(), local_name) File.mkdir_p!(pack_dir) files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end) @@ -249,7 +250,7 @@ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = Creates an empty pack named `name` which then can be updated via the admin UI. """ def create(conn, %{"name" => name}) do - pack_dir = Path.join(@emoji_dir_path, name) + pack_dir = Path.join(emoji_dir_path(), name) if not File.exists?(pack_dir) do File.mkdir_p!(pack_dir) @@ -273,7 +274,7 @@ def create(conn, %{"name" => name}) do Deletes the pack `name` and all it's files. """ def delete(conn, %{"name" => name}) do - pack_dir = Path.join(@emoji_dir_path, name) + pack_dir = Path.join(emoji_dir_path(), name) case File.rm_rf(pack_dir) do {:ok, _} -> @@ -292,7 +293,7 @@ def delete(conn, %{"name" => name}) do `new_data` is the new metadata for the pack, that will replace the old metadata. """ def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do - pack_file_p = Path.join([@emoji_dir_path, name, "pack.json"]) + pack_file_p = Path.join([emoji_dir_path(), name, "pack.json"]) full_pack = Jason.decode!(File.read!(pack_file_p)) @@ -376,7 +377,7 @@ def update_file( conn, %{"pack_name" => pack_name, "action" => "add", "shortcode" => shortcode} = params ) do - pack_dir = Path.join(@emoji_dir_path, pack_name) + pack_dir = Path.join(emoji_dir_path(), pack_name) pack_file_p = Path.join(pack_dir, "pack.json") full_pack = Jason.decode!(File.read!(pack_file_p)) @@ -424,7 +425,7 @@ def update_file(conn, %{ "action" => "remove", "shortcode" => shortcode }) do - pack_dir = Path.join(@emoji_dir_path, pack_name) + pack_dir = Path.join(emoji_dir_path(), pack_name) pack_file_p = Path.join(pack_dir, "pack.json") full_pack = Jason.decode!(File.read!(pack_file_p)) @@ -459,7 +460,7 @@ def update_file( conn, %{"pack_name" => pack_name, "action" => "update", "shortcode" => shortcode} = params ) do - pack_dir = Path.join(@emoji_dir_path, pack_name) + pack_dir = Path.join(emoji_dir_path(), pack_name) pack_file_p = Path.join(pack_dir, "pack.json") full_pack = Jason.decode!(File.read!(pack_file_p)) @@ -529,11 +530,11 @@ def update_file(conn, %{"action" => action}) do assumed to be emojis and stored in the new `pack.json` file. """ def import_from_fs(conn, _params) do - with {:ok, results} <- File.ls(@emoji_dir_path) do + with {:ok, results} <- File.ls(emoji_dir_path()) do imported_pack_names = results |> Enum.filter(fn file -> - dir_path = Path.join(@emoji_dir_path, file) + dir_path = Path.join(emoji_dir_path(), file) # Find the directories that do NOT have pack.json File.dir?(dir_path) and not File.exists?(Path.join(dir_path, "pack.json")) end) @@ -549,7 +550,7 @@ def import_from_fs(conn, _params) do end defp write_pack_json_contents(dir) do - dir_path = Path.join(@emoji_dir_path, dir) + dir_path = Path.join(emoji_dir_path(), dir) emoji_txt_path = Path.join(dir_path, "emoji.txt") files_for_pack = files_for_pack(emoji_txt_path, dir_path) From a6e85215e1bd88e5cda71f75d0d748e58e227cca Mon Sep 17 00:00:00 2001 From: vaartis Date: Tue, 24 Sep 2019 12:15:52 +0000 Subject: [PATCH 214/272] Credo fix (remove parens on function definition) --- lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index e8c4f57a7..b7eede6c9 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -3,7 +3,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do require Logger - def emoji_dir_path() do + def emoji_dir_path do Path.join( Pleroma.Config.get!([:instance, :static_dir]), "emoji" From ba9d35a9049e0d46900d2dd95afd27c09f327a2c Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 24 Sep 2019 19:18:07 +0300 Subject: [PATCH 215/272] Add an API endpoint for listing remote packs --- .../controllers/emoji_api_controller.ex | 52 ++++++++++++++----- lib/pleroma/web/router.ex | 1 + .../pleroma_api/emoji_api_controller_test.exs | 22 ++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index b7eede6c9..cf5a086fe 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -10,6 +10,27 @@ def emoji_dir_path do ) end + @doc """ + Lists packs from the remote instance. + + Since JS cannot ask remote instances for their packs due to CPS, it has to + be done by the server + """ + def list_from(conn, %{"instance_address" => address}) do + address = String.trim(address) + + if shareable_packs_available(address) do + list_resp = + "#{address}/api/pleroma/emoji/packs" |> Tesla.get!() |> Map.get(:body) |> Jason.decode!() + + json(conn, list_resp) + else + conn + |> put_status(:internal_server_error) + |> json(%{error: "The requested instance does not support sharing emoji packs"}) + end + end + @doc """ Lists the packs available on the instance as JSON. @@ -156,6 +177,21 @@ def download_shared(conn, %{"name" => name}) do end end + defp shareable_packs_available(address) do + "#{address}/.well-known/nodeinfo" + |> Tesla.get!() + |> Map.get(:body) + |> Jason.decode!() + |> List.last() + |> Map.get("href") + # Get the actual nodeinfo address and fetch it + |> Tesla.get!() + |> Map.get(:body) + |> Jason.decode!() + |> get_in(["metadata", "features"]) + |> Enum.member?("shareable_emoji_packs") + end + @doc """ An admin endpoint to request downloading a pack named `pack_name` from the instance `instance_address`. @@ -164,21 +200,9 @@ def download_shared(conn, %{"name" => name}) do from that instance, otherwise it will be downloaded from the fallback source, if there is one. """ def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do - shareable_packs_available = - "#{address}/.well-known/nodeinfo" - |> Tesla.get!() - |> Map.get(:body) - |> Jason.decode!() - |> List.last() - |> Map.get("href") - # Get the actual nodeinfo address and fetch it - |> Tesla.get!() - |> Map.get(:body) - |> Jason.decode!() - |> get_in(["metadata", "features"]) - |> Enum.member?("shareable_emoji_packs") + address = String.trim(address) - if shareable_packs_available do + if shareable_packs_available(address) do full_pack = "#{address}/api/pleroma/emoji/packs/list" |> Tesla.get!() diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e583093d2..8bc051936 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -222,6 +222,7 @@ defmodule Pleroma.Web.Router do put("/:name", EmojiAPIController, :create) delete("/:name", EmojiAPIController, :delete) post("/download_from", EmojiAPIController, :download_from) + post("/list_from", EmojiAPIController, :list_from) end scope "/packs" do diff --git a/test/web/pleroma_api/emoji_api_controller_test.exs b/test/web/pleroma_api/emoji_api_controller_test.exs index c5a553692..166a0201d 100644 --- a/test/web/pleroma_api/emoji_api_controller_test.exs +++ b/test/web/pleroma_api/emoji_api_controller_test.exs @@ -33,6 +33,28 @@ test "shared & non-shared pack information in list_packs is ok" do refute pack["pack"]["can-download"] end + test "listing remote packs" do + admin = insert(:user, info: %{is_admin: true}) + conn = build_conn() |> assign(:user, admin) + + resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + + mock(fn + %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> + json([%{href: "https://example.com/nodeinfo/2.1.json"}]) + + %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> + json(%{metadata: %{features: ["shareable_emoji_packs"]}}) + + %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> + json(resp) + end) + + assert conn + |> post(emoji_api_path(conn, :list_from), %{instance_address: "https://example.com"}) + |> json_response(200) == resp + end + test "downloading a shared pack from download_shared" do conn = build_conn() From 118d6dcdf4b2c81b4cbe51fd43977722b3eee164 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 24 Sep 2019 19:38:05 +0300 Subject: [PATCH 216/272] Fix nodeinfo handling --- .../web/pleroma_api/controllers/emoji_api_controller.ex | 1 + test/web/pleroma_api/emoji_api_controller_test.exs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index cf5a086fe..545ad80c9 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -182,6 +182,7 @@ defp shareable_packs_available(address) do |> Tesla.get!() |> Map.get(:body) |> Jason.decode!() + |> Map.get("links") |> List.last() |> Map.get("href") # Get the actual nodeinfo address and fetch it diff --git a/test/web/pleroma_api/emoji_api_controller_test.exs b/test/web/pleroma_api/emoji_api_controller_test.exs index 166a0201d..93a507a01 100644 --- a/test/web/pleroma_api/emoji_api_controller_test.exs +++ b/test/web/pleroma_api/emoji_api_controller_test.exs @@ -41,7 +41,7 @@ test "listing remote packs" do mock(fn %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> - json([%{href: "https://example.com/nodeinfo/2.1.json"}]) + json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> json(%{metadata: %{features: ["shareable_emoji_packs"]}}) @@ -77,13 +77,13 @@ test "downloading shared & unshared packs from another instance via download_fro mock(fn %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} -> - json([%{href: "https://old-instance/nodeinfo/2.1.json"}]) + json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]}) %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> json(%{metadata: %{features: []}}) %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> - json([%{href: "https://example.com/nodeinfo/2.1.json"}]) + json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> json(%{metadata: %{features: ["shareable_emoji_packs"]}}) From 1fd9c60f8706441d38eb4c17417df80e3cf220b1 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 24 Sep 2019 22:20:48 +0300 Subject: [PATCH 217/272] Fix emoji tags for shareable packs to be "pack:{name}" --- lib/pleroma/emoji/loader.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/emoji/loader.ex b/lib/pleroma/emoji/loader.ex index a29de0a33..4f4ee51d1 100644 --- a/lib/pleroma/emoji/loader.ex +++ b/lib/pleroma/emoji/loader.ex @@ -99,7 +99,7 @@ defp load_pack(pack_dir, emoji_groups) do contents["files"] |> Enum.map(fn {name, rel_file} -> filename = Path.join("/emoji/#{pack_name}", rel_file) - {name, filename, pack_name} + {name, filename, ["pack:#{pack_name}"]} end) else # Load from emoji.txt / all files From d87be2ec96912b147ad8fb6b17c1ee00d7d30a7f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 25 Sep 2019 15:59:04 +0300 Subject: [PATCH 218/272] Don't embed the first page in inboxes/outboxes and refactor the views to follow View/Controller pattern Note that I mentioned the change in 1.1 section because I intend to backport this, if this is not needed I will move it back to Unreleased. --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- .../activity_pub/activity_pub_controller.ex | 70 ++++++++++++++-- .../web/activity_pub/views/user_view.ex | 83 +++---------------- .../activity_pub_controller_test.exs | 6 +- .../web/activity_pub/views/user_view_test.exs | 16 +++- 6 files changed, 90 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 649fbc0be..2d6ddd5d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Improve digest email template – Pagination: (optional) return `total` alongside with `items` when paginating - Add `rel="ugc"` to all links in statuses, to prevent SEO spam +- ActivityPub: The first page in inboxes/outboxes is no longer embedded. ### Fixed - Following from Osada diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1cf8b6151..a97afa665 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -834,7 +834,7 @@ defp restrict_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do defp restrict_muted_reblogs(query, _), do: query - defp exclude_poll_votes(query, %{"include_poll_votes" => "true"}), do: query + defp exclude_poll_votes(query, %{"include_poll_votes" => true}), do: query defp exclude_poll_votes(query, _) do if has_named_binding?(query, :object) do diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 9eb86106f..c3e7edf57 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -231,13 +231,42 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname}) d end end - def outbox(conn, %{"nickname" => nickname} = params) do + def outbox(conn, %{"nickname" => nickname, "page" => page?} = params) + when page? in [true, "true"] do + with %User{} = user <- User.get_cached_by_nickname(nickname), + {:ok, user} <- User.ensure_keys_present(user), + activities <- + (if params["max_id"] do + ActivityPub.fetch_user_activities(user, nil, %{ + "max_id" => params["max_id"], + # This is a hack because postgres generates inefficient queries when filtering by 'Answer', + # poll votes will be hidden by the visibility filter in this case anyway + "include_poll_votes" => true, + "limit" => 10 + }) + else + ActivityPub.fetch_user_activities(user, nil, %{ + "limit" => 10, + "include_poll_votes" => true + }) + end) do + conn + |> put_resp_content_type("application/activity+json") + |> put_view(UserView) + |> render("activity_collection_page.json", %{ + activities: activities, + iri: "#{user.ap_id}/outbox" + }) + end + end + + def outbox(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname(nickname), {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_content_type("application/activity+json") |> put_view(UserView) - |> render("outbox.json", %{user: user, max_id: params["max_id"]}) + |> render("activity_collection.json", %{iri: "#{user.ap_id}/outbox"}) end end @@ -315,12 +344,37 @@ def whoami(_conn, _params), do: {:error, :not_found} def read_inbox( %{assigns: %{user: %{nickname: nickname} = user}} = conn, - %{"nickname" => nickname} = params - ) do - conn - |> put_resp_content_type("application/activity+json") - |> put_view(UserView) - |> render("inbox.json", user: user, max_id: params["max_id"]) + %{"nickname" => nickname, "page" => page?} = params + ) + when page? in [true, "true"] do + with activities <- + (if params["max_id"] do + ActivityPub.fetch_activities([user.ap_id | user.following], %{ + "max_id" => params["max_id"], + "limit" => 10 + }) + else + ActivityPub.fetch_activities([user.ap_id | user.following], %{"limit" => 10}) + end) do + conn + |> put_resp_content_type("application/activity+json") + |> put_view(UserView) + |> render("activity_collection_page.json", %{ + activities: activities, + iri: "#{user.ap_id}/inbox" + }) + end + end + + def read_inbox(%{assigns: %{user: %{nickname: nickname} = user}} = conn, %{ + "nickname" => nickname + }) do + with {:ok, user} <- User.ensure_keys_present(user) do + conn + |> put_resp_content_type("application/activity+json") + |> put_view(UserView) + |> render("activity_collection.json", %{iri: "#{user.ap_id}/inbox"}) + end end def read_inbox(%{assigns: %{user: nil}} = conn, %{"nickname" => nickname}) do diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 352d856fa..5dbb5992f 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do alias Pleroma.Keys alias Pleroma.Repo alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Endpoint @@ -210,20 +209,16 @@ def render("followers.json", %{user: user} = opts) do |> Map.merge(Utils.make_json_ld_header()) end - def render("outbox.json", %{user: user, max_id: max_qid}) do - params = %{ - "limit" => "10" + def render("activity_collection.json", %{iri: iri}) do + %{ + "id" => iri, + "type" => "OrderedCollection", + "first" => "#{iri}?page=true" } + |> Map.merge(Utils.make_json_ld_header()) + end - params = - if max_qid != nil do - Map.put(params, "max_id", max_qid) - else - params - end - - activities = ActivityPub.fetch_user_activities(user, nil, params) - + def render("activity_collection_page.json", %{activities: activities, iri: iri}) do # this is sorted chronologically, so first activity is the newest (max) {max_id, min_id, collection} = if length(activities) > 0 do @@ -243,71 +238,15 @@ def render("outbox.json", %{user: user, max_id: max_qid}) do } end - iri = "#{user.ap_id}/outbox" - page = %{ - "id" => "#{iri}?max_id=#{max_id}", + "id" => "#{iri}?max_id=#{max_id}&page=true", "type" => "OrderedCollectionPage", "partOf" => iri, "orderedItems" => collection, - "next" => "#{iri}?max_id=#{min_id}" + "next" => "#{iri}?max_id=#{min_id}&page=true" } - if max_qid == nil do - %{ - "id" => iri, - "type" => "OrderedCollection", - "first" => page - } - |> Map.merge(Utils.make_json_ld_header()) - else - page |> Map.merge(Utils.make_json_ld_header()) - end - end - - def render("inbox.json", %{user: user, max_id: max_qid}) do - params = %{ - "limit" => "10" - } - - params = - if max_qid != nil do - Map.put(params, "max_id", max_qid) - else - params - end - - activities = ActivityPub.fetch_activities([user.ap_id | user.following], params) - - min_id = Enum.at(Enum.reverse(activities), 0).id - max_id = Enum.at(activities, 0).id - - collection = - Enum.map(activities, fn act -> - {:ok, data} = Transmogrifier.prepare_outgoing(act.data) - data - end) - - iri = "#{user.ap_id}/inbox" - - page = %{ - "id" => "#{iri}?max_id=#{max_id}", - "type" => "OrderedCollectionPage", - "partOf" => iri, - "orderedItems" => collection, - "next" => "#{iri}?max_id=#{min_id}" - } - - if max_qid == nil do - %{ - "id" => iri, - "type" => "OrderedCollection", - "first" => page - } - |> Map.merge(Utils.make_json_ld_header()) - else - page |> Map.merge(Utils.make_json_ld_header()) - end + page |> Map.merge(Utils.make_json_ld_header()) end def collection(collection, iri, page, show_items \\ true, total \\ nil) do diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 9e8e420ec..ab52044ae 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -479,7 +479,7 @@ test "it returns a note activity in a collection", %{conn: conn} do conn |> assign(:user, user) |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}/inbox") + |> get("/users/#{user.nickname}/inbox?page=true") assert response(conn, 200) =~ note_object.data["content"] end @@ -567,7 +567,7 @@ test "it returns a note activity in a collection", %{conn: conn} do conn = conn |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}/outbox") + |> get("/users/#{user.nickname}/outbox?page=true") assert response(conn, 200) =~ note_object.data["content"] end @@ -579,7 +579,7 @@ test "it returns an announce activity in a collection", %{conn: conn} do conn = conn |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}/outbox") + |> get("/users/#{user.nickname}/outbox?page=true") assert response(conn, 200) =~ announce_activity.data["object"] end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 78b0408ee..3155749aa 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -159,7 +159,7 @@ test "sets correct totalItems when follows are hidden but the follow counter is end end - test "outbox paginates correctly" do + test "activity collection page aginates correctly" do user = insert(:user) posts = @@ -171,13 +171,21 @@ test "outbox paginates correctly" do # outbox sorts chronologically, newest first, with ten per page posts = Enum.reverse(posts) - %{"first" => %{"next" => next_url}} = - UserView.render("outbox.json", %{user: user, max_id: nil}) + %{"next" => next_url} = + UserView.render("activity_collection_page.json", %{ + iri: "#{user.ap_id}/outbox", + activities: Enum.take(posts, 10) + }) next_id = Enum.at(posts, 9).id assert next_url =~ next_id - %{"next" => next_url} = UserView.render("outbox.json", %{user: user, max_id: next_id}) + %{"next" => next_url} = + UserView.render("activity_collection_page.json", %{ + iri: "#{user.ap_id}/outbox", + activities: Enum.take(Enum.drop(posts, 10), 10) + }) + next_id = Enum.at(posts, 19).id assert next_url =~ next_id end From 1ddd403339655674ca634a876151c4346c87c515 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 25 Sep 2019 13:20:48 +0000 Subject: [PATCH 219/272] Apply suggestion to lib/pleroma/web/activity_pub/activity_pub_controller.ex --- .../activity_pub/activity_pub_controller.ex | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index c3e7edf57..aa1620009 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -234,22 +234,23 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname}) d def outbox(conn, %{"nickname" => nickname, "page" => page?} = params) when page? in [true, "true"] do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- User.ensure_keys_present(user), - activities <- - (if params["max_id"] do - ActivityPub.fetch_user_activities(user, nil, %{ - "max_id" => params["max_id"], - # This is a hack because postgres generates inefficient queries when filtering by 'Answer', - # poll votes will be hidden by the visibility filter in this case anyway - "include_poll_votes" => true, - "limit" => 10 - }) - else - ActivityPub.fetch_user_activities(user, nil, %{ - "limit" => 10, - "include_poll_votes" => true - }) - end) do + {:ok, user} <- User.ensure_keys_present(user) do + activities = + if params["max_id"] do + ActivityPub.fetch_user_activities(user, nil, %{ + "max_id" => params["max_id"], + # This is a hack because postgres generates inefficient queries when filtering by 'Answer', + # poll votes will be hidden by the visibility filter in this case anyway + "include_poll_votes" => true, + "limit" => 10 + }) + else + ActivityPub.fetch_user_activities(user, nil, %{ + "limit" => 10, + "include_poll_votes" => true + }) + end + conn |> put_resp_content_type("application/activity+json") |> put_view(UserView) From c7d8ccd0c417aab59253a446ed0ffc973448536e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 25 Sep 2019 16:26:47 +0300 Subject: [PATCH 220/272] Remove useless with clause --- .../activity_pub/activity_pub_controller.ex | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index aa1620009..60abe1e1d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -348,23 +348,23 @@ def read_inbox( %{"nickname" => nickname, "page" => page?} = params ) when page? in [true, "true"] do - with activities <- - (if params["max_id"] do - ActivityPub.fetch_activities([user.ap_id | user.following], %{ - "max_id" => params["max_id"], - "limit" => 10 - }) - else - ActivityPub.fetch_activities([user.ap_id | user.following], %{"limit" => 10}) - end) do - conn - |> put_resp_content_type("application/activity+json") - |> put_view(UserView) - |> render("activity_collection_page.json", %{ - activities: activities, - iri: "#{user.ap_id}/inbox" - }) - end + activities = + if params["max_id"] do + ActivityPub.fetch_activities([user.ap_id | user.following], %{ + "max_id" => params["max_id"], + "limit" => 10 + }) + else + ActivityPub.fetch_activities([user.ap_id | user.following], %{"limit" => 10}) + end + + conn + |> put_resp_content_type("application/activity+json") + |> put_view(UserView) + |> render("activity_collection_page.json", %{ + activities: activities, + iri: "#{user.ap_id}/inbox" + }) end def read_inbox(%{assigns: %{user: %{nickname: nickname} = user}} = conn, %{ From f2880d7d29836b16ae6825fbda85c21496fc42b5 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 25 Sep 2019 16:36:46 +0300 Subject: [PATCH 221/272] Credo considered harmful --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 60abe1e1d..8112f6642 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -239,8 +239,8 @@ def outbox(conn, %{"nickname" => nickname, "page" => page?} = params) if params["max_id"] do ActivityPub.fetch_user_activities(user, nil, %{ "max_id" => params["max_id"], - # This is a hack because postgres generates inefficient queries when filtering by 'Answer', - # poll votes will be hidden by the visibility filter in this case anyway + # This is a hack because postgres generates inefficient queries when filtering by + # 'Answer', poll votes will be hidden by the visibility filter in this case anyway "include_poll_votes" => true, "limit" => 10 }) From f92d7d52c20e951d31f0dedc16bde3aeb6687374 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 25 Sep 2019 13:38:45 +0000 Subject: [PATCH 222/272] Apply suggestion to lib/pleroma/web/activity_pub/views/user_view.ex --- lib/pleroma/web/activity_pub/views/user_view.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 5dbb5992f..4e37be5db 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -238,15 +238,14 @@ def render("activity_collection_page.json", %{activities: activities, iri: iri}) } end - page = %{ + %{ "id" => "#{iri}?max_id=#{max_id}&page=true", "type" => "OrderedCollectionPage", "partOf" => iri, "orderedItems" => collection, "next" => "#{iri}?max_id=#{min_id}&page=true" } - - page |> Map.merge(Utils.make_json_ld_header()) + |> Map.merge(Utils.make_json_ld_header()) end def collection(collection, iri, page, show_items \\ true, total \\ nil) do From dd4263da5a93a022ba7c46fb1cb4687f8cb1c790 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 25 Sep 2019 17:47:22 +0000 Subject: [PATCH 223/272] Apply suggestion to test/tasks/instance_test.exs --- test/tasks/instance_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tasks/instance_test.exs b/test/tasks/instance_test.exs index a3b0dcb50..6d7eed4c1 100644 --- a/test/tasks/instance_test.exs +++ b/test/tasks/instance_test.exs @@ -10,7 +10,7 @@ defmodule Pleroma.InstanceTest do on_exit(fn -> File.rm_rf(tmp_path()) - static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/") + static_dir = Pleroma.Config.get([:instance, :static_dir], "test/instance_static/") if File.exists?(static_dir) do File.rm_rf(Path.join(static_dir, "robots.txt")) From b057f2ae9e12558efd2b1ff78afa2fa11106b695 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 25 Sep 2019 23:16:35 +0200 Subject: [PATCH 224/272] mix.lock: Bump hackney to 1.15.2 Closes: https://git.pleroma.social/pleroma/pleroma/issues/1267 --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 24b34c09c..530fbb0b4 100644 --- a/mix.lock +++ b/mix.lock @@ -39,7 +39,7 @@ "gen_stage": {:hex, :gen_stage, "0.14.2", "6a2a578a510c5bfca8a45e6b27552f613b41cf584b58210f017088d3d17d0b14", [:mix], [], "hexpm"}, "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"}, - "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]}, @@ -84,7 +84,7 @@ "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"}, "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"}, "swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, From 5fb72170a72e61f0b8035fba63b7bbdff7acde05 Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Thu, 26 Sep 2019 02:57:41 +0000 Subject: [PATCH 225/272] Revert "add _discoverable_ keyword into ActivityPub @context" This reverts commit 3aef4bdf8f37efd1055a84c5fca12ec4559a17f5. --- CHANGELOG.md | 1 + lib/pleroma/user/info.ex | 8 ++++++-- lib/pleroma/web/activity_pub/activity_pub.ex | 4 +++- lib/pleroma/web/activity_pub/views/user_view.ex | 3 ++- .../controllers/mastodon_api_controller.ex | 3 ++- lib/pleroma/web/mastodon_api/views/account_view.ex | 6 +++++- priv/static/schemas/litepub-0.1.jsonld | 1 + test/web/mastodon_api/views/account_view_test.exs | 12 +++++++++--- 8 files changed, 29 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d6ddd5d6..a853a6913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Admin API: Added moderation log - Web response cache (currently, enabled for ActivityPub) - Mastodon API: Added an endpoint to get multiple statuses by IDs (`GET /api/v1/statuses/?ids[]=1&ids[]=2`) +- ActivityPub: Add ActivityPub actor's `discoverable` parameter. ### Changed - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 99745f496..1d0f0c7f4 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -54,6 +54,7 @@ defmodule Pleroma.User.Info do field(:pleroma_settings_store, :map, default: %{}) field(:fields, {:array, :map}, default: nil) field(:raw_fields, {:array, :map}, default: []) + field(:discoverable, :boolean, default: false) field(:notification_settings, :map, default: %{ @@ -277,7 +278,8 @@ def remote_user_creation(info, params) do :hide_follows_count, :follower_count, :fields, - :following_count + :following_count, + :discoverable ]) |> validate_fields(true) end @@ -295,6 +297,7 @@ def user_upgrade(info, params, remote? \\ false) do :hide_follows, :fields, :hide_followers, + :discoverable, :hide_followers_count, :hide_follows_count ]) @@ -318,7 +321,8 @@ def profile_update(info, params) do :skip_thread_containment, :fields, :raw_fields, - :pleroma_settings_store + :pleroma_settings_store, + :discoverable ]) |> validate_fields() end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index ff29efd43..8d0a57623 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1001,6 +1001,7 @@ defp object_to_user_data(data) do locked = data["manuallyApprovesFollowers"] || false data = Transmogrifier.maybe_fix_user_object(data) + discoverable = data["discoverable"] || false user_data = %{ ap_id: data["id"], @@ -1009,7 +1010,8 @@ defp object_to_user_data(data) do source_data: data, banner: banner, fields: fields, - locked: locked + locked: locked, + discoverable: discoverable }, avatar: avatar, name: data["name"], diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 4e37be5db..993307287 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -106,7 +106,8 @@ def render("user.json", %{user: user}) do }, "endpoints" => endpoints, "attachment" => fields, - "tag" => (user.info.source_data["tag"] || []) ++ emoji_tags + "tag" => (user.info.source_data["tag"] || []) ++ emoji_tags, + "discoverable" => user.info.discoverable } |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index bb81b061e..239cfac9f 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -153,7 +153,8 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do :hide_follows, :hide_favorites, :show_role, - :skip_thread_containment + :skip_thread_containment, + :discoverable ] |> Enum.reduce(%{}, fn key, acc -> add_if_present(acc, params, to_string(key), key, fn value -> diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 195dd124b..a23aeea9b 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -116,6 +116,8 @@ defp do_render("account.json", %{user: user} = opts) do bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for])) relationship = render("relationship.json", %{user: opts[:for], target: user}) + discoverable = user.info.discoverable + %{ id: to_string(user.id), username: username_from_nickname(user.nickname), @@ -139,7 +141,9 @@ defp do_render("account.json", %{user: user} = opts) do note: HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), sensitive: false, fields: raw_fields, - pleroma: %{} + pleroma: %{ + discoverable: discoverable + } }, # Pleroma extension diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld index 57ed05eba..6e4bb29b1 100644 --- a/priv/static/schemas/litepub-0.1.jsonld +++ b/priv/static/schemas/litepub-0.1.jsonld @@ -11,6 +11,7 @@ "@id": "ostatus:conversation", "@type": "@id" }, + "discoverable": "toot:discoverable", "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", "ostatus": "http://ostatus.org#", "schema": "http://schema.org", diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 6206107f7..f2f334992 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -67,7 +67,9 @@ test "Represent a user account" do source: %{ note: "valid html", sensitive: false, - pleroma: %{}, + pleroma: %{ + discoverable: false + }, fields: [] }, pleroma: %{ @@ -137,7 +139,9 @@ test "Represent a Service(bot) account" do source: %{ note: user.bio, sensitive: false, - pleroma: %{}, + pleroma: %{ + discoverable: false + }, fields: [] }, pleroma: %{ @@ -310,7 +314,9 @@ test "represent an embedded relationship" do source: %{ note: user.bio, sensitive: false, - pleroma: %{}, + pleroma: %{ + discoverable: false + }, fields: [] }, pleroma: %{ From eed774d058bfac2d36fd79faa915394a97baa6db Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 24 Sep 2019 16:10:54 +0700 Subject: [PATCH 226/272] Add CommonAPI.ActivityDraft --- lib/pleroma/web/common_api/activity_draft.ex | 222 ++++++++++++++++++ lib/pleroma/web/common_api/common_api.ex | 103 ++------ lib/pleroma/web/common_api/utils.ex | 124 +++++----- lib/pleroma/web/controller_helper.ex | 2 +- .../controllers/mastodon_api_controller.ex | 47 ++-- 5 files changed, 322 insertions(+), 176 deletions(-) create mode 100644 lib/pleroma/web/common_api/activity_draft.ex diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex new file mode 100644 index 000000000..b4480bd18 --- /dev/null +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -0,0 +1,222 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.CommonAPI.ActivityDraft do + alias Pleroma.Activity + alias Pleroma.Conversation.Participation + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.CommonAPI.Utils + + import Pleroma.Web.Gettext + + defstruct valid?: true, + errors: [], + user: nil, + params: %{}, + status: nil, + summary: nil, + full_payload: nil, + attachments: [], + in_reply_to: nil, + in_reply_to_conversation: nil, + visibility: nil, + expires_at: nil, + poll: nil, + emoji: %{}, + content_html: nil, + mentions: [], + tags: [], + to: [], + cc: [], + context: nil, + sensitive: false, + object: nil, + preview?: false, + changes: %{} + + def create(user, params) do + %__MODULE__{user: user} + |> put_params(params) + |> status() + |> summary() + |> attachments() + |> full_payload() + |> in_reply_to() + |> in_reply_to_conversation() + |> visibility() + |> expires_at() + |> poll() + |> content() + |> to_and_cc() + |> context() + |> sensitive() + |> object() + |> preview?() + |> changes() + |> validate() + end + + defp put_params(draft, params) do + params = Map.put_new(params, "in_reply_to_status_id", params["in_reply_to_id"]) + %__MODULE__{draft | params: params} + end + + defp status(%{params: %{"status" => status}} = draft) do + %__MODULE__{draft | status: String.trim(status)} + end + + defp summary(%{params: params} = draft) do + %__MODULE__{draft | summary: Map.get(params, "spoiler_text", "")} + end + + defp full_payload(%{status: status, summary: summary} = draft) do + full_payload = String.trim(status <> summary) + + case Utils.validate_character_limit(full_payload, draft.attachments) do + :ok -> %__MODULE__{draft | full_payload: full_payload} + {:error, message} -> add_error(draft, message) + end + end + + defp attachments(%{params: params} = draft) do + attachments = Utils.attachments_from_ids(params) + %__MODULE__{draft | attachments: attachments} + end + + defp in_reply_to(draft) do + case Map.get(draft.params, "in_reply_to_status_id") do + "" -> draft + nil -> draft + id -> %__MODULE__{draft | in_reply_to: Activity.get_by_id(id)} + end + end + + defp in_reply_to_conversation(draft) do + in_reply_to_conversation = Participation.get(draft.params["in_reply_to_conversation_id"]) + %__MODULE__{draft | in_reply_to_conversation: in_reply_to_conversation} + end + + defp visibility(%{params: params} = draft) do + case CommonAPI.get_visibility(params, draft.in_reply_to, draft.in_reply_to_conversation) do + {visibility, "direct"} when visibility != "direct" -> + add_error(draft, dgettext("errors", "The message visibility must be direct")) + + {visibility, _} -> + %__MODULE__{draft | visibility: visibility} + end + end + + defp expires_at(draft) do + case CommonAPI.check_expiry_date(draft.params["expires_in"]) do + {:ok, expires_at} -> %__MODULE__{draft | expires_at: expires_at} + {:error, message} -> add_error(draft, message) + end + end + + defp poll(draft) do + case Utils.make_poll_data(draft.params) do + {:ok, {poll, poll_emoji}} -> + %__MODULE__{draft | poll: poll, emoji: Map.merge(draft.emoji, poll_emoji)} + + {:error, message} -> + add_error(draft, message) + end + end + + defp content(draft) do + {content_html, mentions, tags} = + Utils.make_content_html( + draft.status, + draft.attachments, + draft.params, + draft.visibility + ) + + %__MODULE__{draft | content_html: content_html, mentions: mentions, tags: tags} + end + + defp to_and_cc(%{valid?: false} = draft), do: draft + + defp to_and_cc(draft) do + addressed_users = + draft.mentions + |> Enum.map(fn {_, mentioned_user} -> mentioned_user.ap_id end) + |> Utils.get_addressed_users(draft.params["to"]) + + {to, cc} = + Utils.get_to_and_cc( + draft.user, + addressed_users, + draft.in_reply_to, + draft.visibility, + draft.in_reply_to_conversation + ) + + %__MODULE__{draft | to: to, cc: cc} + end + + defp context(draft) do + context = Utils.make_context(draft.in_reply_to, draft.in_reply_to_conversation) + %__MODULE__{draft | context: context} + end + + defp sensitive(draft) do + sensitive = draft.params["sensitive"] || Enum.member?(draft.tags, {"#nsfw", "nsfw"}) + %__MODULE__{draft | sensitive: sensitive} + end + + defp object(%{valid?: false} = draft), do: draft + + defp object(draft) do + emoji = Map.merge(Pleroma.Emoji.Formatter.get_emoji_map(draft.full_payload), draft.emoji) + + object = + Utils.make_note_data( + draft.user.ap_id, + draft.to, + draft.context, + draft.content_html, + draft.attachments, + draft.in_reply_to, + draft.tags, + draft.summary, + draft.cc, + draft.sensitive, + draft.poll + ) + |> Map.put("emoji", emoji) + + %__MODULE__{draft | object: object} + end + + defp preview?(draft) do + preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"]) || false + %__MODULE__{draft | preview?: preview?} + end + + defp changes(%{valid?: false} = draft), do: draft + + defp changes(draft) do + direct? = draft.visibility == "direct" + + changes = + %{ + to: draft.to, + actor: draft.user, + context: draft.context, + object: draft.object, + additional: %{"cc" => draft.cc, "directMessage" => direct?} + } + |> Utils.maybe_add_list_data(draft.user, draft.visibility) + + %__MODULE__{draft | changes: changes} + end + + defp add_error(draft, message) do + %__MODULE__{draft | valid?: false, errors: [message | draft.errors]} + end + + defp validate(%{valid?: true} = draft), do: {:ok, draft} + defp validate(%{errors: [message | _]}), do: {:error, message} +end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 4a74dc16f..d34bb7285 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.CommonAPI do alias Pleroma.Activity alias Pleroma.ActivityExpiration alias Pleroma.Conversation.Participation - alias Pleroma.Emoji alias Pleroma.Object alias Pleroma.ThreadMute alias Pleroma.User @@ -173,9 +172,7 @@ defp normalize_and_validate_choice_indices(choices, count) do end) end - def get_visibility(_, _, %Participation{}) do - {"direct", "direct"} - end + def get_visibility(_, _, %Participation{}), do: {"direct", "direct"} def get_visibility(%{"visibility" => visibility}, in_reply_to, _) when visibility in ~w{public unlisted private direct}, @@ -201,9 +198,9 @@ def get_replied_to_visibility(activity) do end end - defp check_expiry_date({:ok, nil} = res), do: res + def check_expiry_date({:ok, nil} = res), do: res - defp check_expiry_date({:ok, in_seconds}) do + def check_expiry_date({:ok, in_seconds}) do expiry = NaiveDateTime.utc_now() |> NaiveDateTime.add(in_seconds) if ActivityExpiration.expires_late_enough?(expiry) do @@ -213,97 +210,27 @@ defp check_expiry_date({:ok, in_seconds}) do end end - defp check_expiry_date(expiry_str) do + def check_expiry_date(expiry_str) do Ecto.Type.cast(:integer, expiry_str) |> check_expiry_date() end - def post(user, %{"status" => status} = data) do - limit = Pleroma.Config.get([:instance, :limit]) - - with status <- String.trim(status), - attachments <- attachments_from_ids(data), - in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]), - in_reply_to_conversation <- Participation.get(data["in_reply_to_conversation_id"]), - {visibility, in_reply_to_visibility} <- - get_visibility(data, in_reply_to, in_reply_to_conversation), - {_, false} <- - {:private_to_public, in_reply_to_visibility == "direct" && visibility != "direct"}, - {content_html, mentions, tags} <- - make_content_html( - status, - attachments, - data, - visibility - ), - mentioned_users <- for({_, mentioned_user} <- mentions, do: mentioned_user.ap_id), - addressed_users <- get_addressed_users(mentioned_users, data["to"]), - {poll, poll_emoji} <- make_poll_data(data), - {to, cc} <- - get_to_and_cc(user, addressed_users, in_reply_to, visibility, in_reply_to_conversation), - context <- make_context(in_reply_to, in_reply_to_conversation), - cw <- data["spoiler_text"] || "", - sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}), - {:ok, expires_at} <- check_expiry_date(data["expires_in"]), - full_payload <- String.trim(status <> cw), - :ok <- validate_character_limit(full_payload, attachments, limit), - object <- - make_note_data( - user.ap_id, - to, - context, - content_html, - attachments, - in_reply_to, - tags, - cw, - cc, - sensitive, - poll - ), - object <- put_emoji(object, full_payload, poll_emoji) do - preview? = Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false - direct? = visibility == "direct" - - result = - %{ - to: to, - actor: user, - context: context, - object: object, - additional: %{"cc" => cc, "directMessage" => direct?} - } - |> maybe_add_list_data(user, visibility) - |> ActivityPub.create(preview?) - - if expires_at do - with {:ok, activity} <- result do - {:ok, _} = ActivityExpiration.create(activity, expires_at) - end - end - - result - else - {:private_to_public, true} -> - {:error, dgettext("errors", "The message visibility must be direct")} - - {:error, _} = e -> - e - - e -> - {:error, e} + def post(user, %{"status" => _} = data) do + with {:ok, draft} <- Pleroma.Web.CommonAPI.ActivityDraft.create(user, data) do + draft.changes + |> ActivityPub.create(draft.preview?) + |> maybe_create_activity_expiration(draft.expires_at) end end - # parse and put emoji to object data - defp put_emoji(map, text, emojis) do - Map.put( - map, - "emoji", - Map.merge(Emoji.Formatter.get_emoji_map(text), emojis) - ) + defp maybe_create_activity_expiration({:ok, activity}, %NaiveDateTime{} = expires_at) do + with {:ok, _} <- ActivityExpiration.create(activity, expires_at) do + {:ok, activity} + end end + defp maybe_create_activity_expiration(result, _), do: result + # Updates the emojis for a user based on their profile def update(user) do emoji = emoji_from_profile(user) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 52fbc162b..8093a56a6 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do import Pleroma.Web.Gettext + import Pleroma.Web.ControllerHelper, only: [truthy_param?: 1] alias Calendar.Strftime alias Pleroma.Activity @@ -41,14 +42,6 @@ def get_by_id_or_ap_id(id) do end end - def get_replied_to_activity(""), do: nil - - def get_replied_to_activity(id) when not is_nil(id) do - Activity.get_by_id(id) - end - - def get_replied_to_activity(_), do: nil - def attachments_from_ids(%{"media_ids" => ids, "descriptions" => desc} = _) do attachments_from_ids_descs(ids, desc) end @@ -159,70 +152,74 @@ def maybe_add_list_data(activity_params, user, {:list, list_id}) do def maybe_add_list_data(activity_params, _, _), do: activity_params + def make_poll_data(%{"poll" => %{"expires_in" => expires_in}} = data) + when is_binary(expires_in) do + # In some cases mastofe sends out strings instead of integers + data + |> put_in(["poll", "expires_in"], String.to_integer(expires_in)) + |> make_poll_data() + end + def make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_in}} = data) when is_list(options) do - %{max_expiration: max_expiration, min_expiration: min_expiration} = - limits = Pleroma.Config.get([:instance, :poll_limits]) + limits = Pleroma.Config.get([:instance, :poll_limits]) - # XXX: There is probably a cleaner way of doing this - try do - # In some cases mastofe sends out strings instead of integers - expires_in = if is_binary(expires_in), do: String.to_integer(expires_in), else: expires_in - - if Enum.count(options) > limits.max_options do - raise ArgumentError, message: "Poll can't contain more than #{limits.max_options} options" - end - - {poll, emoji} = + with :ok <- validate_poll_expiration(expires_in, limits), + :ok <- validate_poll_options_amount(options, limits), + :ok <- validate_poll_options_length(options, limits) do + {option_notes, emoji} = Enum.map_reduce(options, %{}, fn option, emoji -> - if String.length(option) > limits.max_option_chars do - raise ArgumentError, - message: - "Poll options cannot be longer than #{limits.max_option_chars} characters each" - end + note = %{ + "name" => option, + "type" => "Note", + "replies" => %{"type" => "Collection", "totalItems" => 0} + } - {%{ - "name" => option, - "type" => "Note", - "replies" => %{"type" => "Collection", "totalItems" => 0} - }, Map.merge(emoji, Emoji.Formatter.get_emoji_map(option))} + {note, Map.merge(emoji, Emoji.Formatter.get_emoji_map(option))} end) - case expires_in do - expires_in when expires_in > max_expiration -> - raise ArgumentError, message: "Expiration date is too far in the future" - - expires_in when expires_in < min_expiration -> - raise ArgumentError, message: "Expiration date is too soon" - - _ -> - :noop - end - end_time = NaiveDateTime.utc_now() |> NaiveDateTime.add(expires_in) |> NaiveDateTime.to_iso8601() - poll = - if Pleroma.Web.ControllerHelper.truthy_param?(data["poll"]["multiple"]) do - %{"type" => "Question", "anyOf" => poll, "closed" => end_time} - else - %{"type" => "Question", "oneOf" => poll, "closed" => end_time} - end + key = if truthy_param?(data["poll"]["multiple"]), do: "anyOf", else: "oneOf" + poll = %{"type" => "Question", key => option_notes, "closed" => end_time} - {poll, emoji} - rescue - e in ArgumentError -> e.message + {:ok, {poll, emoji}} end end def make_poll_data(%{"poll" => poll}) when is_map(poll) do - "Invalid poll" + {:error, "Invalid poll"} end def make_poll_data(_data) do - {%{}, %{}} + {:ok, {%{}, %{}}} + end + + defp validate_poll_options_amount(options, %{max_options: max_options}) do + if Enum.count(options) > max_options do + {:error, "Poll can't contain more than #{max_options} options"} + else + :ok + end + end + + defp validate_poll_options_length(options, %{max_option_chars: max_option_chars}) do + if Enum.any?(options, &(String.length(&1) > max_option_chars)) do + {:error, "Poll options cannot be longer than #{max_option_chars} characters each"} + else + :ok + end + end + + defp validate_poll_expiration(expires_in, %{min_expiration: min, max_expiration: max}) do + cond do + expires_in > max -> {:error, "Expiration date is too far in the future"} + expires_in < min -> {:error, "Expiration date is too soon"} + true -> :ok + end end def make_content_html( @@ -347,25 +344,25 @@ def make_note_data( attachments, in_reply_to, tags, - cw \\ nil, + summary \\ nil, cc \\ [], sensitive \\ false, - merge \\ %{} + extra_params \\ %{} ) do %{ "type" => "Note", "to" => to, "cc" => cc, "content" => content_html, - "summary" => cw, - "sensitive" => !Enum.member?(["false", "False", "0", false], sensitive), + "summary" => summary, + "sensitive" => truthy_param?(sensitive), "context" => context, "attachment" => attachments, "actor" => actor, "tag" => Keyword.values(tags) |> Enum.uniq() } |> add_in_reply_to(in_reply_to) - |> Map.merge(merge) + |> Map.merge(extra_params) end defp add_in_reply_to(object, nil), do: object @@ -571,15 +568,16 @@ def make_answer_data(%User{ap_id: ap_id}, object, name) do } end - def validate_character_limit(full_payload, attachments, limit) do + def validate_character_limit("" = _full_payload, [] = _attachments) do + {:error, dgettext("errors", "Cannot post an empty status without attachments")} + end + + def validate_character_limit(full_payload, _attachments) do + limit = Pleroma.Config.get([:instance, :limit]) length = String.length(full_payload) if length < limit do - if length > 0 or Enum.count(attachments) > 0 do - :ok - else - {:error, dgettext("errors", "Cannot post an empty status without attachments")} - end + :ok else {:error, dgettext("errors", "The status is over the character limit")} end diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index b53a01955..e90bf842e 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.ControllerHelper do use Pleroma.Web, :controller # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html - @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"] + @falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"] def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil def truthy_param?(value), do: value not in @falsy_param_values diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 1e88ff7fe..28d0e58f3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -575,14 +575,11 @@ def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => schedule end end - def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do - params = - params - |> Map.put("in_reply_to_status_id", params["in_reply_to_id"]) - - scheduled_at = params["scheduled_at"] - - if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do + def post_status( + %{assigns: %{user: user}} = conn, + %{"status" => _, "scheduled_at" => scheduled_at} = params + ) do + if ScheduledActivity.far_enough?(scheduled_at) do with {:ok, scheduled_activity} <- ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do conn @@ -590,24 +587,26 @@ def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do |> render("show.json", %{scheduled_activity: scheduled_activity}) end else - params = Map.drop(params, ["scheduled_at"]) + post_status(conn, Map.drop(params, ["scheduled_at"])) + end + end - case CommonAPI.post(user, params) do - {:error, message} -> - conn - |> put_status(:unprocessable_entity) - |> json(%{error: message}) + def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do + case CommonAPI.post(user, params) do + {:ok, activity} -> + conn + |> put_view(StatusView) + |> try_render("status.json", %{ + activity: activity, + for: user, + as: :activity, + with_direct_conversation_id: true + }) - {:ok, activity} -> - conn - |> put_view(StatusView) - |> try_render("status.json", %{ - activity: activity, - for: user, - as: :activity, - with_direct_conversation_id: true - }) - end + {:error, message} -> + conn + |> put_status(:unprocessable_entity) + |> json(%{error: message}) end end From de3e90e536ea0759b024155aee307cc340db3cf1 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 23 Sep 2019 18:52:41 +0700 Subject: [PATCH 227/272] Add ActivityDraft.with_valid/2 --- lib/pleroma/web/common_api/activity_draft.ex | 25 +++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index b4480bd18..aa7c8c381 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -40,20 +40,20 @@ def create(user, params) do |> put_params(params) |> status() |> summary() - |> attachments() |> full_payload() - |> in_reply_to() - |> in_reply_to_conversation() - |> visibility() |> expires_at() |> poll() + |> with_valid(&in_reply_to/1) + |> with_valid(&attachments/1) + |> with_valid(&in_reply_to_conversation/1) + |> with_valid(&visibility/1) |> content() - |> to_and_cc() - |> context() + |> with_valid(&to_and_cc/1) + |> with_valid(&context/1) |> sensitive() - |> object() + |> with_valid(&object/1) |> preview?() - |> changes() + |> with_valid(&changes/1) |> validate() end @@ -136,8 +136,6 @@ defp content(draft) do %__MODULE__{draft | content_html: content_html, mentions: mentions, tags: tags} end - defp to_and_cc(%{valid?: false} = draft), do: draft - defp to_and_cc(draft) do addressed_users = draft.mentions @@ -166,8 +164,6 @@ defp sensitive(draft) do %__MODULE__{draft | sensitive: sensitive} end - defp object(%{valid?: false} = draft), do: draft - defp object(draft) do emoji = Map.merge(Pleroma.Emoji.Formatter.get_emoji_map(draft.full_payload), draft.emoji) @@ -195,8 +191,6 @@ defp preview?(draft) do %__MODULE__{draft | preview?: preview?} end - defp changes(%{valid?: false} = draft), do: draft - defp changes(draft) do direct? = draft.visibility == "direct" @@ -213,6 +207,9 @@ defp changes(draft) do %__MODULE__{draft | changes: changes} end + defp with_valid(%{valid?: true} = draft, func), do: func.(draft) + defp with_valid(draft, _func), do: draft + defp add_error(draft, message) do %__MODULE__{draft | valid?: false, errors: [message | draft.errors]} end From c57ad0a4020fe88521b83d471fb8b71d637fddf1 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 24 Sep 2019 15:56:20 +0700 Subject: [PATCH 228/272] Cleanup CommonAPI --- lib/pleroma/web/common_api/common_api.ex | 159 ++++++++++------------- lib/pleroma/web/common_api/utils.ex | 12 +- 2 files changed, 79 insertions(+), 92 deletions(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index d34bb7285..a00e4b0d8 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -17,14 +17,11 @@ defmodule Pleroma.Web.CommonAPI do import Pleroma.Web.CommonAPI.Utils def follow(follower, followed) do + timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout]) + with {:ok, follower} <- User.maybe_direct_follow(follower, followed), {:ok, activity} <- ActivityPub.follow(follower, followed), - {:ok, follower, followed} <- - User.wait_and_refresh( - Pleroma.Config.get([:activitypub, :follow_handshake_timeout]), - follower, - followed - ) do + {:ok, follower, followed} <- User.wait_and_refresh(timeout, follower, followed) do {:ok, follower, followed, activity} end end @@ -75,8 +72,7 @@ def delete(activity_id, user) do {:ok, delete} <- ActivityPub.delete(object) do {:ok, delete} else - _ -> - {:error, dgettext("errors", "Could not delete")} + _ -> {:error, dgettext("errors", "Could not delete")} end end @@ -86,18 +82,16 @@ def repeat(id_or_ap_id, user) do nil <- Utils.get_existing_announce(user.ap_id, object) do ActivityPub.announce(user, object) else - _ -> - {:error, dgettext("errors", "Could not repeat")} + _ -> {:error, dgettext("errors", "Could not repeat")} end end def unrepeat(id_or_ap_id, user) do - with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), - object <- Object.normalize(activity) do + with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id) do + object = Object.normalize(activity) ActivityPub.unannounce(user, object) else - _ -> - {:error, dgettext("errors", "Could not unrepeat")} + _ -> {:error, dgettext("errors", "Could not unrepeat")} end end @@ -107,30 +101,23 @@ def favorite(id_or_ap_id, user) do nil <- Utils.get_existing_like(user.ap_id, object) do ActivityPub.like(user, object) else - _ -> - {:error, dgettext("errors", "Could not favorite")} + _ -> {:error, dgettext("errors", "Could not favorite")} end end def unfavorite(id_or_ap_id, user) do - with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), - object <- Object.normalize(activity) do + with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id) do + object = Object.normalize(activity) ActivityPub.unlike(user, object) else - _ -> - {:error, dgettext("errors", "Could not unfavorite")} + _ -> {:error, dgettext("errors", "Could not unfavorite")} end end - def vote(user, object, choices) do - with "Question" <- object.data["type"], - {:author, false} <- {:author, object.data["actor"] == user.ap_id}, - {:existing_votes, []} <- {:existing_votes, Utils.get_existing_votes(user.ap_id, object)}, - {options, max_count} <- get_options_and_max_count(object), - option_count <- Enum.count(options), - {:choice_check, {choices, true}} <- - {:choice_check, normalize_and_validate_choice_indices(choices, option_count)}, - {:count_check, true} <- {:count_check, Enum.count(choices) <= max_count} do + def vote(user, %{data: %{"type" => "Question"}} = object, choices) do + with :ok <- validate_not_author(object, user), + :ok <- validate_existing_votes(user, object), + {:ok, options, choices} <- normalize_and_validate_choices(choices, object) do answer_activities = Enum.map(choices, fn index -> answer_data = make_answer_data(user, object, Enum.at(options, index)["name"]) @@ -149,27 +136,37 @@ def vote(user, object, choices) do object = Object.get_cached_by_ap_id(object.data["id"]) {:ok, answer_activities, object} - else - {:author, _} -> {:error, dgettext("errors", "Poll's author can't vote")} - {:existing_votes, _} -> {:error, dgettext("errors", "Already voted")} - {:choice_check, {_, false}} -> {:error, dgettext("errors", "Invalid indices")} - {:count_check, false} -> {:error, dgettext("errors", "Too many choices")} end end - defp get_options_and_max_count(object) do - if Map.has_key?(object.data, "anyOf") do - {object.data["anyOf"], Enum.count(object.data["anyOf"])} + defp validate_not_author(%{data: %{"actor" => ap_id}}, %{ap_id: ap_id}), + do: {:error, dgettext("errors", "Poll's author can't vote")} + + defp validate_not_author(_, _), do: :ok + + defp validate_existing_votes(%{ap_id: ap_id}, object) do + if Utils.get_existing_votes(ap_id, object) == [] do + :ok else - {object.data["oneOf"], 1} + {:error, dgettext("errors", "Already voted")} end end - defp normalize_and_validate_choice_indices(choices, count) do - Enum.map_reduce(choices, true, fn index, valid -> - index = if is_binary(index), do: String.to_integer(index), else: index - {index, if(valid, do: index < count, else: valid)} - end) + defp get_options_and_max_count(%{data: %{"anyOf" => any_of}}), do: {any_of, Enum.count(any_of)} + defp get_options_and_max_count(%{data: %{"oneOf" => one_of}}), do: {one_of, 1} + + defp normalize_and_validate_choices(choices, object) do + choices = Enum.map(choices, fn i -> if is_binary(i), do: String.to_integer(i), else: i end) + {options, max_count} = get_options_and_max_count(object) + count = Enum.count(options) + + with {_, true} <- {:valid_choice, Enum.all?(choices, &(&1 < count))}, + {_, true} <- {:count_check, Enum.count(choices) <= max_count} do + {:ok, options, choices} + else + {:valid_choice, _} -> {:error, dgettext("errors", "Invalid indices")} + {:count_check, _} -> {:error, dgettext("errors", "Too many choices")} + end end def get_visibility(_, _, %Participation{}), do: {"direct", "direct"} @@ -194,7 +191,7 @@ def get_replied_to_visibility(nil), do: nil def get_replied_to_visibility(activity) do with %Object{} = object <- Object.normalize(activity) do - Pleroma.Web.ActivityPub.Visibility.get_visibility(object) + Visibility.get_visibility(object) end end @@ -234,13 +231,12 @@ defp maybe_create_activity_expiration(result, _), do: result # Updates the emojis for a user based on their profile def update(user) do emoji = emoji_from_profile(user) - source_data = user.info |> Map.get(:source_data, {}) |> Map.put("tag", emoji) + source_data = user.info |> Map.get(:source_data, %{}) |> Map.put("tag", emoji) user = - with {:ok, user} <- User.update_info(user, &User.Info.set_source_data(&1, source_data)) do - user - else - _e -> user + case User.update_info(user, &User.Info.set_source_data(&1, source_data)) do + {:ok, user} -> user + _ -> user end ActivityPub.update(%{ @@ -255,14 +251,8 @@ def update(user) do def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do with %Activity{ actor: ^user_ap_id, - data: %{ - "type" => "Create" - }, - object: %Object{ - data: %{ - "type" => "Note" - } - } + data: %{"type" => "Create"}, + object: %Object{data: %{"type" => "Note"}} } = activity <- get_by_id_or_ap_id(id_or_ap_id), true <- Visibility.is_public?(activity), {:ok, _user} <- User.update_info(user, &User.Info.add_pinnned_activity(&1, activity)) do @@ -299,51 +289,46 @@ def remove_mute(user, activity) do def thread_muted?(%{id: nil} = _user, _activity), do: false def thread_muted?(user, activity) do - with [] <- ThreadMute.check_muted(user.id, activity.data["context"]) do - false - else - _ -> true + ThreadMute.check_muted(user.id, activity.data["context"]) != [] + end + + def report(user, %{"account_id" => account_id} = data) do + with {:ok, account} <- get_reported_account(account_id), + {:ok, {content_html, _, _}} <- make_report_content_html(data["comment"]), + {:ok, statuses} <- get_report_statuses(account, data) do + ActivityPub.flag(%{ + context: Utils.generate_context_id(), + actor: user, + account: account, + statuses: statuses, + content: content_html, + forward: data["forward"] || false + }) end end - def report(user, data) do - with {:account_id, %{"account_id" => account_id}} <- {:account_id, data}, - {:account, %User{} = account} <- {:account, User.get_cached_by_id(account_id)}, - {:ok, {content_html, _, _}} <- make_report_content_html(data["comment"]), - {:ok, statuses} <- get_report_statuses(account, data), - {:ok, activity} <- - ActivityPub.flag(%{ - context: Utils.generate_context_id(), - actor: user, - account: account, - statuses: statuses, - content: content_html, - forward: data["forward"] || false - }) do - {:ok, activity} - else - {:error, err} -> {:error, err} - {:account_id, %{}} -> {:error, dgettext("errors", "Valid `account_id` required")} - {:account, nil} -> {:error, dgettext("errors", "Account not found")} + def report(_user, _params), do: {:error, dgettext("errors", "Valid `account_id` required")} + + defp get_reported_account(account_id) do + case User.get_cached_by_id(account_id) do + %User{} = account -> {:ok, account} + _ -> {:error, dgettext("errors", "Account not found")} end end def update_report_state(activity_id, state) do - with %Activity{} = activity <- Activity.get_by_id(activity_id), - {:ok, activity} <- Utils.update_report_state(activity, state) do - {:ok, activity} + with %Activity{} = activity <- Activity.get_by_id(activity_id) do + Utils.update_report_state(activity, state) else nil -> {:error, :not_found} - {:error, reason} -> {:error, reason} _ -> {:error, dgettext("errors", "Could not update state")} end end def update_activity_scope(activity_id, opts \\ %{}) do with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), - {:ok, activity} <- toggle_sensitive(activity, opts), - {:ok, activity} <- set_visibility(activity, opts) do - {:ok, activity} + {:ok, activity} <- toggle_sensitive(activity, opts) do + set_visibility(activity, opts) else nil -> {:error, :not_found} {:error, reason} -> {:error, reason} diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 8093a56a6..88a5f434a 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -231,7 +231,7 @@ def make_content_html( no_attachment_links = data |> Map.get("no_attachment_links", Config.get([:instance, :no_attachment_links])) - |> Kernel.in([true, "true"]) + |> truthy_param?() content_type = get_content_type(data["content_type"]) @@ -431,12 +431,14 @@ def confirm_current_password(user, password) do end end - def emoji_from_profile(%{info: _info} = user) do - (Emoji.Formatter.get_emoji(user.bio) ++ Emoji.Formatter.get_emoji(user.name)) - |> Enum.map(fn {shortcode, %Emoji{file: url}} -> + def emoji_from_profile(%User{bio: bio, name: name}) do + [bio, name] + |> Enum.map(&Emoji.Formatter.get_emoji/1) + |> Enum.concat() + |> Enum.map(fn {shortcode, %Emoji{file: path}} -> %{ "type" => "Emoji", - "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"}, + "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{path}"}, "name" => ":#{shortcode}:" } end) From 3572cf29b7374947ebfbb42a20d370a75f5f0a40 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 26 Sep 2019 10:53:42 +0700 Subject: [PATCH 229/272] Extract timeline actions from `MastodonAPIController` into `TimelineController` --- lib/pleroma/web/controller_helper.ex | 2 +- .../controllers/mastodon_api_controller.ex | 125 +------- .../controllers/timeline_controller.ex | 136 ++++++++ lib/pleroma/web/router.ex | 10 +- .../controllers/timeline_controller_test.exs | 291 ++++++++++++++++++ .../mastodon_api_controller_test.exs | 283 +---------------- 6 files changed, 438 insertions(+), 409 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex create mode 100644 test/web/mastodon_api/controllers/timeline_controller_test.exs diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index b53a01955..e90bf842e 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.ControllerHelper do use Pleroma.Web, :controller # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html - @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"] + @falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"] def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil def truthy_param?(value), do: value not in @falsy_param_values diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 1e88ff7fe..74a8b5055 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller import Pleroma.Web.ControllerHelper, - only: [json_response: 3, add_link_headers: 2, add_link_headers: 3] + only: [json_response: 3, add_link_headers: 2, truthy_param?: 1] alias Ecto.Changeset alias Pleroma.Activity @@ -44,7 +44,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.OAuth.Token alias Pleroma.Web.TwitterAPI.TwitterAPI - alias Pleroma.Web.ControllerHelper import Ecto.Query require Logger @@ -156,7 +155,7 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do ] |> Enum.reduce(%{}, fn key, acc -> add_if_present(acc, params, to_string(key), key, fn value -> - {:ok, ControllerHelper.truthy_param?(value)} + {:ok, truthy_param?(value)} end) end) |> add_if_present(params, "default_scope", :default_scope) @@ -344,43 +343,6 @@ def custom_emojis(conn, _params) do json(conn, mastodon_emoji) end - def home_timeline(%{assigns: %{user: user}} = conn, params) do - params = - params - |> Map.put("type", ["Create", "Announce"]) - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> Map.put("user", user) - - activities = - [user.ap_id | user.following] - |> ActivityPub.fetch_activities(params) - |> Enum.reverse() - - conn - |> add_link_headers(activities) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - end - - def public_timeline(%{assigns: %{user: user}} = conn, params) do - local_only = params["local"] in [true, "True", "true", "1"] - - activities = - params - |> Map.put("type", ["Create", "Announce"]) - |> Map.put("local_only", local_only) - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> ActivityPub.fetch_public_activities() - |> Enum.reverse() - - conn - |> add_link_headers(activities, %{"local" => local_only}) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - end - def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do params = @@ -400,25 +362,6 @@ def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do end end - def dm_timeline(%{assigns: %{user: user}} = conn, params) do - params = - params - |> Map.put("type", "Create") - |> Map.put("blocking_user", user) - |> Map.put("user", user) - |> Map.put(:visibility, "direct") - - activities = - [user.ap_id] - |> ActivityPub.fetch_activities_query(params) - |> Pagination.fetch_paginated(params) - - conn - |> add_link_headers(activities) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - end - def get_statuses(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do limit = 100 @@ -822,45 +765,6 @@ def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do end end - def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do - local_only = params["local"] in [true, "True", "true", "1"] - - tags = - [params["tag"], params["any"]] - |> List.flatten() - |> Enum.uniq() - |> Enum.filter(& &1) - |> Enum.map(&String.downcase(&1)) - - tag_all = - params["all"] || - [] - |> Enum.map(&String.downcase(&1)) - - tag_reject = - params["none"] || - [] - |> Enum.map(&String.downcase(&1)) - - activities = - params - |> Map.put("type", "Create") - |> Map.put("local_only", local_only) - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> Map.put("user", user) - |> Map.put("tag", tags) - |> Map.put("tag_all", tag_all) - |> Map.put("tag_reject", tag_reject) - |> ActivityPub.fetch_public_activities() - |> Enum.reverse() - - conn - |> add_link_headers(activities, %{"local" => local_only}) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - end - def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do with %User{} = user <- User.get_cached_by_id(id), followers <- MastodonAPI.get_followers(user, params) do @@ -1173,31 +1077,6 @@ def account_lists(%{assigns: %{user: user}} = conn, %{"id" => account_id}) do json(conn, res) end - def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do - with %Pleroma.List{title: _title, following: following} <- Pleroma.List.get(id, user) do - params = - params - |> Map.put("type", "Create") - |> Map.put("blocking_user", user) - |> Map.put("user", user) - |> Map.put("muting_user", user) - - # we must filter the following list for the user to avoid leaking statuses the user - # does not actually have permission to see (for more info, peruse security issue #270). - activities = - following - |> Enum.filter(fn x -> x in user.following end) - |> ActivityPub.fetch_activities_bounded(following, params) - |> Enum.reverse() - - conn - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - else - _e -> render_error(conn, :forbidden, "Error.") - end - end - def index(%{assigns: %{user: user}} = conn, _params) do token = get_session(conn, :oauth_token) diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex new file mode 100644 index 000000000..bb8b0eb32 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -0,0 +1,136 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.TimelineController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, + only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1] + + alias Pleroma.Pagination + alias Pleroma.Web.ActivityPub.ActivityPub + + plug(:put_view, Pleroma.Web.MastodonAPI.StatusView) + + # GET /api/v1/timelines/home + def home(%{assigns: %{user: user}} = conn, params) do + params = + params + |> Map.put("type", ["Create", "Announce"]) + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> Map.put("user", user) + + recipients = [user.ap_id | user.following] + + activities = + recipients + |> ActivityPub.fetch_activities(params) + |> Enum.reverse() + + conn + |> add_link_headers(activities) + |> render("index.json", activities: activities, for: user, as: :activity) + end + + # GET /api/v1/timelines/direct + def direct(%{assigns: %{user: user}} = conn, params) do + params = + params + |> Map.put("type", "Create") + |> Map.put("blocking_user", user) + |> Map.put("user", user) + |> Map.put(:visibility, "direct") + + activities = + [user.ap_id] + |> ActivityPub.fetch_activities_query(params) + |> Pagination.fetch_paginated(params) + + conn + |> add_link_headers(activities) + |> render("index.json", activities: activities, for: user, as: :activity) + end + + # GET /api/v1/timelines/public + def public(%{assigns: %{user: user}} = conn, params) do + local_only = truthy_param?(params["local"]) + + activities = + params + |> Map.put("type", ["Create", "Announce"]) + |> Map.put("local_only", local_only) + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> ActivityPub.fetch_public_activities() + |> Enum.reverse() + + conn + |> add_link_headers(activities, %{"local" => local_only}) + |> render("index.json", activities: activities, for: user, as: :activity) + end + + # GET /api/v1/timelines/tag/:tag + def hashtag(%{assigns: %{user: user}} = conn, params) do + local_only = truthy_param?(params["local"]) + + tags = + [params["tag"], params["any"]] + |> List.flatten() + |> Enum.uniq() + |> Enum.filter(& &1) + |> Enum.map(&String.downcase(&1)) + + tag_all = + params + |> Map.get("all", []) + |> Enum.map(&String.downcase(&1)) + + tag_reject = + params + |> Map.get("none", []) + |> Enum.map(&String.downcase(&1)) + + activities = + params + |> Map.put("type", "Create") + |> Map.put("local_only", local_only) + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> Map.put("user", user) + |> Map.put("tag", tags) + |> Map.put("tag_all", tag_all) + |> Map.put("tag_reject", tag_reject) + |> ActivityPub.fetch_public_activities() + |> Enum.reverse() + + conn + |> add_link_headers(activities, %{"local" => local_only}) + |> render("index.json", activities: activities, for: user, as: :activity) + end + + # GET /api/v1/timelines/list/:list_id + def list(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do + with %Pleroma.List{title: _title, following: following} <- Pleroma.List.get(id, user) do + params = + params + |> Map.put("type", "Create") + |> Map.put("blocking_user", user) + |> Map.put("user", user) + |> Map.put("muting_user", user) + + # we must filter the following list for the user to avoid leaking statuses the user + # does not actually have permission to see (for more info, peruse security issue #270). + activities = + following + |> Enum.filter(fn x -> x in user.following end) + |> ActivityPub.fetch_activities_bounded(following, params) + |> Enum.reverse() + + render(conn, "index.json", activities: activities, for: user, as: :activity) + else + _e -> render_error(conn, :forbidden, "Error.") + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 316c895ee..2575481ff 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -319,8 +319,8 @@ defmodule Pleroma.Web.Router do get("/blocks", MastodonAPIController, :blocks) get("/mutes", MastodonAPIController, :mutes) - get("/timelines/home", MastodonAPIController, :home_timeline) - get("/timelines/direct", MastodonAPIController, :dm_timeline) + get("/timelines/home", TimelineController, :home) + get("/timelines/direct", TimelineController, :direct) get("/favourites", MastodonAPIController, :favourites) get("/bookmarks", MastodonAPIController, :bookmarks) @@ -466,9 +466,9 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_read_or_public) - get("/timelines/public", MastodonAPIController, :public_timeline) - get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline) - get("/timelines/list/:list_id", MastodonAPIController, :list_timeline) + get("/timelines/public", TimelineController, :public) + get("/timelines/tag/:tag", TimelineController, :hashtag) + get("/timelines/list/:list_id", TimelineController, :list) get("/statuses", MastodonAPIController, :get_statuses) get("/statuses/:id", MastodonAPIController, :get_status) diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs new file mode 100644 index 000000000..d3652d964 --- /dev/null +++ b/test/web/mastodon_api/controllers/timeline_controller_test.exs @@ -0,0 +1,291 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + import Tesla.Mock + + alias Pleroma.Config + alias Pleroma.User + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.OStatus + + clear_config([:instance, :public]) + + setup do + mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + test "the home timeline", %{conn: conn} do + user = insert(:user) + following = insert(:user) + + {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/timelines/home") + + assert Enum.empty?(json_response(conn, :ok)) + + {:ok, user} = User.follow(user, following) + + conn = + build_conn() + |> assign(:user, user) + |> get("/api/v1/timelines/home") + + assert [%{"content" => "test"}] = json_response(conn, :ok) + end + + describe "public" do + @tag capture_log: true + test "the public timeline", %{conn: conn} do + following = insert(:user) + + {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) + + {:ok, [_activity]} = + OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") + + conn = get(conn, "/api/v1/timelines/public", %{"local" => "False"}) + + assert length(json_response(conn, :ok)) == 2 + + conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "True"}) + + assert [%{"content" => "test"}] = json_response(conn, :ok) + + conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "1"}) + + assert [%{"content" => "test"}] = json_response(conn, :ok) + end + + test "the public timeline when public is set to false", %{conn: conn} do + Config.put([:instance, :public], false) + + assert %{"error" => "This resource requires authentication."} == + conn + |> get("/api/v1/timelines/public", %{"local" => "False"}) + |> json_response(:forbidden) + end + + test "the public timeline includes only public statuses for an authenticated user" do + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"}) + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"}) + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"}) + {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) + + res_conn = get(conn, "/api/v1/timelines/public") + assert length(json_response(res_conn, 200)) == 1 + end + end + + describe "direct" do + test "direct timeline", %{conn: conn} do + user_one = insert(:user) + user_two = insert(:user) + + {:ok, user_two} = User.follow(user_two, user_one) + + {:ok, direct} = + CommonAPI.post(user_one, %{ + "status" => "Hi @#{user_two.nickname}!", + "visibility" => "direct" + }) + + {:ok, _follower_only} = + CommonAPI.post(user_one, %{ + "status" => "Hi @#{user_two.nickname}!", + "visibility" => "private" + }) + + # Only direct should be visible here + res_conn = + conn + |> assign(:user, user_two) + |> get("api/v1/timelines/direct") + + [status] = json_response(res_conn, :ok) + + assert %{"visibility" => "direct"} = status + assert status["url"] != direct.data["id"] + + # User should be able to see their own direct message + res_conn = + build_conn() + |> assign(:user, user_one) + |> get("api/v1/timelines/direct") + + [status] = json_response(res_conn, :ok) + + assert %{"visibility" => "direct"} = status + + # Both should be visible here + res_conn = + conn + |> assign(:user, user_two) + |> get("api/v1/timelines/home") + + [_s1, _s2] = json_response(res_conn, :ok) + + # Test pagination + Enum.each(1..20, fn _ -> + {:ok, _} = + CommonAPI.post(user_one, %{ + "status" => "Hi @#{user_two.nickname}!", + "visibility" => "direct" + }) + end) + + res_conn = + conn + |> assign(:user, user_two) + |> get("api/v1/timelines/direct") + + statuses = json_response(res_conn, :ok) + assert length(statuses) == 20 + + res_conn = + conn + |> assign(:user, user_two) + |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]}) + + [status] = json_response(res_conn, :ok) + + assert status["url"] != direct.data["id"] + end + + test "doesn't include DMs from blocked users", %{conn: conn} do + blocker = insert(:user) + blocked = insert(:user) + user = insert(:user) + {:ok, blocker} = User.block(blocker, blocked) + + {:ok, _blocked_direct} = + CommonAPI.post(blocked, %{ + "status" => "Hi @#{blocker.nickname}!", + "visibility" => "direct" + }) + + {:ok, direct} = + CommonAPI.post(user, %{ + "status" => "Hi @#{blocker.nickname}!", + "visibility" => "direct" + }) + + res_conn = + conn + |> assign(:user, user) + |> get("api/v1/timelines/direct") + + [status] = json_response(res_conn, :ok) + assert status["id"] == direct.id + end + end + + describe "list" do + test "list timeline", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."}) + {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) + {:ok, list} = Pleroma.List.create("name", user) + {:ok, list} = Pleroma.List.follow(list, other_user) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/timelines/list/#{list.id}") + + assert [%{"id" => id}] = json_response(conn, :ok) + + assert id == to_string(activity_two.id) + end + + test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) + + {:ok, _activity_two} = + CommonAPI.post(other_user, %{ + "status" => "Marisa is cute.", + "visibility" => "private" + }) + + {:ok, list} = Pleroma.List.create("name", user) + {:ok, list} = Pleroma.List.follow(list, other_user) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/timelines/list/#{list.id}") + + assert [%{"id" => id}] = json_response(conn, :ok) + + assert id == to_string(activity_one.id) + end + end + + describe "hashtag" do + @tag capture_log: true + test "hashtag timeline", %{conn: conn} do + following = insert(:user) + + {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"}) + + {:ok, [_activity]} = + OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") + + nconn = get(conn, "/api/v1/timelines/tag/2hu") + + assert [%{"id" => id}] = json_response(nconn, :ok) + + assert id == to_string(activity.id) + + # works for different capitalization too + nconn = get(conn, "/api/v1/timelines/tag/2HU") + + assert [%{"id" => id}] = json_response(nconn, :ok) + + assert id == to_string(activity.id) + end + + test "multi-hashtag timeline", %{conn: conn} do + user = insert(:user) + + {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"}) + {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"}) + {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"}) + + any_test = get(conn, "/api/v1/timelines/tag/test", %{"any" => ["test1"]}) + + [status_none, status_test1, status_test] = json_response(any_test, :ok) + + assert to_string(activity_test.id) == status_test["id"] + assert to_string(activity_test1.id) == status_test1["id"] + assert to_string(activity_none.id) == status_none["id"] + + restricted_test = + get(conn, "/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]}) + + assert [status_test1] == json_response(restricted_test, :ok) + + all_test = get(conn, "/api/v1/timelines/tag/test", %{"all" => ["none"]}) + + assert [status_none] == json_response(all_test, :ok) + end + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index cd672132b..7f7a89516 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -20,12 +20,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Pleroma.Web.MastodonAPI.FilterView alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Token - alias Pleroma.Web.OStatus alias Pleroma.Web.Push - import Pleroma.Factory + import ExUnit.CaptureLog - import Tesla.Mock + import Pleroma.Factory import Swoosh.TestAssertions + import Tesla.Mock @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" @@ -37,82 +37,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do clear_config([:instance, :public]) clear_config([:rich_media, :enabled]) - test "the home timeline", %{conn: conn} do - user = insert(:user) - following = insert(:user) - - {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/timelines/home") - - assert Enum.empty?(json_response(conn, 200)) - - {:ok, user} = User.follow(user, following) - - conn = - build_conn() - |> assign(:user, user) - |> get("/api/v1/timelines/home") - - assert [%{"content" => "test"}] = json_response(conn, 200) - end - - test "the public timeline", %{conn: conn} do - following = insert(:user) - - capture_log(fn -> - {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) - - {:ok, [_activity]} = - OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") - - conn = - conn - |> get("/api/v1/timelines/public", %{"local" => "False"}) - - assert length(json_response(conn, 200)) == 2 - - conn = - build_conn() - |> get("/api/v1/timelines/public", %{"local" => "True"}) - - assert [%{"content" => "test"}] = json_response(conn, 200) - - conn = - build_conn() - |> get("/api/v1/timelines/public", %{"local" => "1"}) - - assert [%{"content" => "test"}] = json_response(conn, 200) - end) - end - - test "the public timeline when public is set to false", %{conn: conn} do - Config.put([:instance, :public], false) - - assert conn - |> get("/api/v1/timelines/public", %{"local" => "False"}) - |> json_response(403) == %{"error" => "This resource requires authentication."} - end - - test "the public timeline includes only public statuses for an authenticated user" do - user = insert(:user) - - conn = - build_conn() - |> assign(:user, user) - - {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"}) - {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"}) - {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"}) - {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) - - res_conn = get(conn, "/api/v1/timelines/public") - assert length(json_response(res_conn, 200)) == 1 - end - describe "posting statuses" do setup do user = insert(:user) @@ -419,80 +343,6 @@ test "maximum date limit is enforced", %{conn: conn} do end end - test "direct timeline", %{conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - - {:ok, user_two} = User.follow(user_two, user_one) - - {:ok, direct} = - CommonAPI.post(user_one, %{ - "status" => "Hi @#{user_two.nickname}!", - "visibility" => "direct" - }) - - {:ok, _follower_only} = - CommonAPI.post(user_one, %{ - "status" => "Hi @#{user_two.nickname}!", - "visibility" => "private" - }) - - # Only direct should be visible here - res_conn = - conn - |> assign(:user, user_two) - |> get("api/v1/timelines/direct") - - [status] = json_response(res_conn, 200) - - assert %{"visibility" => "direct"} = status - assert status["url"] != direct.data["id"] - - # User should be able to see their own direct message - res_conn = - build_conn() - |> assign(:user, user_one) - |> get("api/v1/timelines/direct") - - [status] = json_response(res_conn, 200) - - assert %{"visibility" => "direct"} = status - - # Both should be visible here - res_conn = - conn - |> assign(:user, user_two) - |> get("api/v1/timelines/home") - - [_s1, _s2] = json_response(res_conn, 200) - - # Test pagination - Enum.each(1..20, fn _ -> - {:ok, _} = - CommonAPI.post(user_one, %{ - "status" => "Hi @#{user_two.nickname}!", - "visibility" => "direct" - }) - end) - - res_conn = - conn - |> assign(:user, user_two) - |> get("api/v1/timelines/direct") - - statuses = json_response(res_conn, 200) - assert length(statuses) == 20 - - res_conn = - conn - |> assign(:user, user_two) - |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]}) - - [status] = json_response(res_conn, 200) - - assert status["url"] != direct.data["id"] - end - test "Conversations", %{conn: conn} do user_one = insert(:user) user_two = insert(:user) @@ -556,33 +406,6 @@ test "Conversations", %{conn: conn} do assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200) end - test "doesn't include DMs from blocked users", %{conn: conn} do - blocker = insert(:user) - blocked = insert(:user) - user = insert(:user) - {:ok, blocker} = User.block(blocker, blocked) - - {:ok, _blocked_direct} = - CommonAPI.post(blocked, %{ - "status" => "Hi @#{blocker.nickname}!", - "visibility" => "direct" - }) - - {:ok, direct} = - CommonAPI.post(user, %{ - "status" => "Hi @#{blocker.nickname}!", - "visibility" => "direct" - }) - - res_conn = - conn - |> assign(:user, user) - |> get("api/v1/timelines/direct") - - [status] = json_response(res_conn, 200) - assert status["id"] == direct.id - end - test "verify_credentials", %{conn: conn} do user = insert(:user) @@ -955,50 +778,6 @@ test "delete a filter", %{conn: conn} do end end - describe "list timelines" do - test "list timeline", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."}) - {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) - {:ok, list} = Pleroma.List.create("name", user) - {:ok, list} = Pleroma.List.follow(list, other_user) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/timelines/list/#{list.id}") - - assert [%{"id" => id}] = json_response(conn, 200) - - assert id == to_string(activity_two.id) - end - - test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) - - {:ok, _activity_two} = - CommonAPI.post(other_user, %{ - "status" => "Marisa is cute.", - "visibility" => "private" - }) - - {:ok, list} = Pleroma.List.create("name", user) - {:ok, list} = Pleroma.List.follow(list, other_user) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/timelines/list/#{list.id}") - - assert [%{"id" => id}] = json_response(conn, 200) - - assert id == to_string(activity_one.id) - end - end - describe "reblogging" do test "reblogs and returns the reblogged status", %{conn: conn} do activity = insert(:note_activity) @@ -1554,62 +1333,6 @@ test "mascot retrieving", %{conn: conn} do assert url =~ "an_image" end - test "hashtag timeline", %{conn: conn} do - following = insert(:user) - - capture_log(fn -> - {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"}) - - {:ok, [_activity]} = - OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") - - nconn = - conn - |> get("/api/v1/timelines/tag/2hu") - - assert [%{"id" => id}] = json_response(nconn, 200) - - assert id == to_string(activity.id) - - # works for different capitalization too - nconn = - conn - |> get("/api/v1/timelines/tag/2HU") - - assert [%{"id" => id}] = json_response(nconn, 200) - - assert id == to_string(activity.id) - end) - end - - test "multi-hashtag timeline", %{conn: conn} do - user = insert(:user) - - {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"}) - {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"}) - {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"}) - - any_test = - conn - |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]}) - - [status_none, status_test1, status_test] = json_response(any_test, 200) - - assert to_string(activity_test.id) == status_test["id"] - assert to_string(activity_test1.id) == status_test1["id"] - assert to_string(activity_none.id) == status_none["id"] - - restricted_test = - conn - |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]}) - - assert [status_test1] == json_response(restricted_test, 200) - - all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]}) - - assert [status_none] == json_response(all_test, 200) - end - test "getting followers", %{conn: conn} do user = insert(:user) other_user = insert(:user) From fc16bec3176bad683dfef1be472f09be1a86928b Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Thu, 26 Sep 2019 09:52:11 +0300 Subject: [PATCH 230/272] Add list_from endpoint to the pleroma_api docs --- docs/api/pleroma_api.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index a469ddfbf..ac5489aa3 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -423,6 +423,15 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * Response: JSON, "ok" and 200 status if the pack was downloaded, or 500 if there were errors downloading the pack +## `POST /api/pleroma/emoji/packs/list_from` +### Requests the instance to list the packs from another instance +* Method `POST` +* Authentication: required +* Params: + * `instance_address`: the address of the instance to download from +* Response: JSON with the pack list, same as if the request was made to that instance's + list endpoint directly + 200 status + ## `GET /api/pleroma/emoji/packs/:name/download_shared` ### Requests a local pack from the instance * Method `GET` From b736312123bd11e8ba87b8b39245c0f441ebd7fb Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Thu, 26 Sep 2019 15:17:36 +0300 Subject: [PATCH 231/272] Update CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a76e6cf8..291c961ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Refreshing poll results for remote polls - Admin API: Add ability to require password reset +- Pleroma API: `GET /api/v1/pleroma/subscription_notifications/` to get list of subscription notifications +- Pleroma API: `GET /api/v1/pleroma/subscription_notifications/:id` to get a subscription notification +- Pleroma API: `POST /api/v1/pleroma/subscription_notifications/clear` to clear all subscription notifications +- Pleroma API: `POST /api/v1/pleroma/subscription_notifications/dismiss` to clear a subscription notification +- Pleroma API: `DELETE /api/v1/pleroma/subscription_notifications/destroy_multiple` to clear multiple subscription notifications ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) @@ -15,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Admin API: Return `total` when querying for reports - Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) - Admin API: Return link alongside with token on password reset +- Mastodon API: notifications no longer include subscription notifications - they are now served from new endpoints in Pleroma API ### Fixed - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) From f249b2381f15f089f5f87f16e467b63d34bbea70 Mon Sep 17 00:00:00 2001 From: kPherox Date: Thu, 26 Sep 2019 16:10:34 +0000 Subject: [PATCH 232/272] Fix code block for admin api document --- docs/api/admin_api.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index d4e08f221..d7ab808d5 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -711,6 +711,7 @@ Compile time settings (need instance reboot): } ] } +``` - Response: From 39a4892929e160186c7cbeef0f2abe6131758511 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 26 Sep 2019 19:20:47 +0300 Subject: [PATCH 233/272] Add docs --- docs/api/admin_api.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index d4e08f221..573111416 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -731,7 +731,11 @@ Compile time settings (need instance reboot): - Method `GET` - Params: - *optional* `page`: **integer** page number - - *optional* `page_size`: **integer** number of users per page (default is `50`) + - *optional* `page_size`: **integer** number of log entries per page (default is `50`) + - *optional* `start_date`: **datetime (ISO 8601)** filter logs by creation date, start from `start_date`. Accepts datetime in ISO 8601 format (YYYY-MM-DDThh:mm:ss), e.g. `2005-08-09T18:31:42` + - *optional* `end_date`: **datetime (ISO 8601)** filter logs by creation date, end by from `end_date`. Accepts datetime in ISO 8601 format (YYYY-MM-DDThh:mm:ss), e.g. 2005-08-09T18:31:42 + - *optional* `user_id`: **integer** filter logs by actor's id + - *optional* `search`: **string** search logs by the log message - Response: ```json From 73ae38ca04df02656bfb239ceba4ffe64879e927 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 26 Sep 2019 21:08:04 +0300 Subject: [PATCH 234/272] add deprecated tag --- .../web/mastodon_api/controllers/mastodon_api_controller.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 5e1977b8e..8f6b3456a 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -1474,6 +1474,8 @@ defp fetch_suggestion_id(attrs) do end end + @doc false + @deprecated "https://github.com/tootsuite/mastodon/pull/11213" def status_card(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do From 3ec81b816f436cf37efd6a133f02b49d84501b59 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 27 Sep 2019 01:16:24 +0300 Subject: [PATCH 235/272] Sync changelogs between master and develop --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9ddb5b03..755b28d5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Improve digest email template – Pagination: (optional) return `total` alongside with `items` when paginating - Add `rel="ugc"` to all links in statuses, to prevent SEO spam -- ActivityPub: The first page in inboxes/outboxes is no longer embedded. ### Fixed - Following from Osada @@ -119,6 +118,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - RichMedia: parsers and their order are configured in `rich_media` config. - RichMedia: add the rich media ttl based on image expiration time. +## [1.0.7] - 2019-09-26 +### Fixed +- Broken federation on Erlang 22 (previous versions of hackney http client were using an option that got deprecated) +### Changed +- ActivityPub: The first page in inboxes/outboxes is no longer embedded. + ## [1.0.6] - 2019-08-14 ### Fixed - MRF: fix use of unserializable keyword lists in describe() implementations From 98d1347a4ea1c296d2f07b9467addc56ef2dc676 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 9 Sep 2019 21:49:02 +0700 Subject: [PATCH 236/272] Extract status actions from `MastodonAPIController` into `StatusController` --- lib/pleroma/bbs/handler.ex | 2 +- .../web/admin_api/admin_api_controller.ex | 4 +- .../controllers/mastodon_api_controller.ex | 264 ---------------- .../controllers/status_controller.ex | 294 ++++++++++++++++++ .../mastodon_api/views/conversation_view.ex | 2 +- .../mastodon_api/views/notification_view.ex | 6 +- .../web/mastodon_api/views/status_view.ex | 16 +- lib/pleroma/web/router.ex | 36 +-- lib/pleroma/web/views/streamer_view.ex | 4 +- test/integration/mastodon_websocket_test.exs | 2 +- test/web/admin_api/views/report_view_test.exs | 2 +- .../views/notification_view_test.exs | 6 +- .../mastodon_api/views/status_view_test.exs | 44 +-- 13 files changed, 354 insertions(+), 328 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/status_controller.ex diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 0a381f592..fa838a4e4 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -42,7 +42,7 @@ defp loop(state) do end def puts_activity(activity) do - status = Pleroma.Web.MastodonAPI.StatusView.render("status.json", %{activity: activity}) + status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity}) IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})") IO.puts(HtmlSanitizeEx.strip_tags(status.content)) IO.puts("") diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 90aef99f7..21da8a7ff 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -513,7 +513,7 @@ def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do conn |> put_view(StatusView) - |> render("status.json", %{activity: activity}) + |> render("show.json", %{activity: activity}) else true -> {:param_cast, nil} @@ -537,7 +537,7 @@ def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do conn |> put_view(StatusView) - |> render("status.json", %{activity: activity}) + |> render("show.json", %{activity: activity}) end end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index e4ae63231..82bba43e5 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -51,28 +51,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do @rate_limited_relations_actions ~w(follow unfollow)a - @rate_limited_status_actions ~w(reblog_status unreblog_status fav_status unfav_status - post_status delete_status)a - - plug( - RateLimiter, - {:status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]} - when action in ~w(reblog_status unreblog_status)a - ) - - plug( - RateLimiter, - {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]} - when action in ~w(fav_status unfav_status)a - ) - plug( RateLimiter, {:relations_id_action, params: ["id", "uri"]} when action in @rate_limited_relations_actions ) plug(RateLimiter, :relations_actions when action in @rate_limited_relations_actions) - plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions) plug(RateLimiter, :app_account_creation when action == :account_register) plug(RateLimiter, :search when action in [:search, :search2, :account_search]) plug(RateLimiter, :password_reset when action == :password_reset) @@ -362,63 +346,6 @@ def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do end end - def get_statuses(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do - limit = 100 - - activities = - ids - |> Enum.take(limit) - |> Activity.all_by_ids_with_object() - |> Enum.filter(&Visibility.visible_for_user?(&1, user)) - - conn - |> put_view(StatusView) - |> render("index.json", activities: activities, for: user, as: :activity) - end - - def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Activity.get_by_id_with_object(id), - true <- Visibility.visible_for_user?(activity, user) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user}) - end - end - - def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Activity.get_by_id(id), - activities <- - ActivityPub.fetch_activities_for_context(activity.data["context"], %{ - "blocking_user" => user, - "user" => user, - "exclude_id" => activity.id - }), - grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do - result = %{ - ancestors: - StatusView.render( - "index.json", - for: user, - activities: grouped_activities[true] || [], - as: :activity - ) - |> Enum.reverse(), - # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart - descendants: - StatusView.render( - "index.json", - for: user, - activities: grouped_activities[false] || [], - as: :activity - ) - |> Enum.reverse() - # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart - } - - json(conn, result) - end - end - def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60), %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]), @@ -518,143 +445,6 @@ def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => schedule end end - def post_status( - %{assigns: %{user: user}} = conn, - %{"status" => _, "scheduled_at" => scheduled_at} = params - ) do - if ScheduledActivity.far_enough?(scheduled_at) do - with {:ok, scheduled_activity} <- - ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) - end - else - post_status(conn, Map.drop(params, ["scheduled_at"])) - end - end - - def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do - case CommonAPI.post(user, params) do - {:ok, activity} -> - conn - |> put_view(StatusView) - |> try_render("status.json", %{ - activity: activity, - for: user, - as: :activity, - with_direct_conversation_id: true - }) - - {:error, message} -> - conn - |> put_status(:unprocessable_entity) - |> json(%{error: message}) - end - end - - def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do - json(conn, %{}) - else - _e -> render_error(conn, :forbidden, "Can't delete this post") - end - end - - def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do - with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user), - %Activity{} = announce <- Activity.normalize(announce.data) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: announce, for: user, as: :activity}) - end - end - - def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do - with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user), - %Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def fav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do - with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user), - %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do - with {:ok, _, _, %{data: %{"id" => id}}} <- CommonAPI.unfavorite(ap_id_or_id, user), - %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def pin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do - with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do - with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Activity.get_by_id_with_object(id), - %User{} = user <- User.get_cached_by_nickname(user.nickname), - true <- Visibility.visible_for_user?(activity, user), - {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Activity.get_by_id_with_object(id), - %User{} = user <- User.get_cached_by_nickname(user.nickname), - true <- Visibility.visible_for_user?(activity, user), - {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do - activity = Activity.get_by_id(id) - - with {:ok, activity} <- CommonAPI.add_mute(user, activity) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - - def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do - activity = Activity.get_by_id(id) - - with {:ok, activity} <- CommonAPI.remove_mute(user, activity) do - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - end - end - def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do id = List.wrap(id) q = from(u in User, where: u.id in ^id) @@ -726,44 +516,6 @@ def get_mascot(%{assigns: %{user: user}} = conn, _params) do |> json(mascot) end - def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Activity.get_by_id_with_object(id), - {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, - %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do - q = from(u in User, where: u.ap_id in ^likes) - - users = - Repo.all(q) - |> Enum.filter(&(not User.blocks?(user, &1))) - - conn - |> put_view(AccountView) - |> render("accounts.json", %{for: user, users: users, as: :user}) - else - {:visible, false} -> {:error, :not_found} - _ -> json(conn, []) - end - end - - def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Activity.get_by_id_with_object(id), - {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, - %Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do - q = from(u in User, where: u.ap_id in ^announces) - - users = - Repo.all(q) - |> Enum.filter(&(not User.blocks?(user, &1))) - - conn - |> put_view(AccountView) - |> render("accounts.json", %{for: user, users: users, as: :user}) - else - {:visible, false} -> {:error, :not_found} - _ -> json(conn, []) - end - end - def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do with %User{} = user <- User.get_cached_by_id(id), followers <- MastodonAPI.get_followers(user, params) do @@ -1394,22 +1146,6 @@ defp fetch_suggestion_id(attrs) do end end - def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do - with %Activity{} = activity <- Activity.get_by_id(status_id), - true <- Visibility.visible_for_user?(activity, user) do - data = - StatusView.render( - "card.json", - Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - ) - - json(conn, data) - else - _e -> - %{} - end - end - def reports(%{assigns: %{user: user}} = conn, params) do case CommonAPI.report(user, params) do {:ok, activity} -> diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex new file mode 100644 index 000000000..89869bda0 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -0,0 +1,294 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.StatusController do + use Pleroma.Web, :controller + + import Pleroma.Web.MastodonAPI.MastodonAPIController, only: [try_render: 3] + + require Ecto.Query + + alias Pleroma.Activity + alias Pleroma.Bookmark + alias Pleroma.Object + alias Pleroma.Plugs.RateLimiter + alias Pleroma.Repo + alias Pleroma.ScheduledActivity + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.AccountView + alias Pleroma.Web.MastodonAPI.ScheduledActivityView + alias Pleroma.Web.MastodonAPI.StatusView + + @rate_limited_status_actions ~w(reblog unreblog favourite unfavourite create delete)a + + plug( + RateLimiter, + {:status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]} + when action in ~w(reblog unreblog)a + ) + + plug( + RateLimiter, + {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]} + when action in ~w(favourite unfavourite)a + ) + + plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions) + + action_fallback(Pleroma.Web.MastodonAPI.FallbackController) + + @doc """ + GET `/api/v1/statuses?ids[]=1&ids[]=2` + + `ids` query param is required + """ + def index(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do + limit = 100 + + activities = + ids + |> Enum.take(limit) + |> Activity.all_by_ids_with_object() + |> Enum.filter(&Visibility.visible_for_user?(&1, user)) + + render(conn, "index.json", activities: activities, for: user, as: :activity) + end + + @doc """ + POST /api/v1/statuses + + Creates a scheduled status when `scheduled_at` param is present and it's far enough + """ + def create( + %{assigns: %{user: user}} = conn, + %{"status" => _, "scheduled_at" => scheduled_at} = params + ) do + params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"]) + + if ScheduledActivity.far_enough?(scheduled_at) do + with {:ok, scheduled_activity} <- + ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do + conn + |> put_view(ScheduledActivityView) + |> render("show.json", scheduled_activity: scheduled_activity) + end + else + create(conn, Map.drop(params, ["scheduled_at"])) + end + end + + @doc """ + POST /api/v1/statuses + + Creates a regular status + """ + def create(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do + params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"]) + + with {:ok, activity} <- CommonAPI.post(user, params) do + try_render(conn, "show.json", + activity: activity, + for: user, + as: :activity, + with_direct_conversation_id: true + ) + else + {:error, message} -> + conn + |> put_status(:unprocessable_entity) + |> json(%{error: message}) + end + end + + @doc "GET /api/v1/statuses/:id" + def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + true <- Visibility.visible_for_user?(activity, user) do + try_render(conn, "show.json", activity: activity, for: user) + end + end + + @doc "DELETE /api/v1/statuses/:id" + def delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do + json(conn, %{}) + else + _e -> render_error(conn, :forbidden, "Can't delete this post") + end + end + + @doc "POST /api/v1/statuses/:id/reblog" + def reblog(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do + with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user), + %Activity{} = announce <- Activity.normalize(announce.data) do + try_render(conn, "show.json", %{activity: announce, for: user, as: :activity}) + end + end + + @doc "POST /api/v1/statuses/:id/unreblog" + def unreblog(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do + with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user), + %Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do + try_render(conn, "show.json", %{activity: activity, for: user, as: :activity}) + end + end + + @doc "POST /api/v1/statuses/:id/favourite" + def favourite(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do + with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user), + %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "POST /api/v1/statuses/:id/unfavourite" + def unfavourite(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do + with {:ok, _, _, %{data: %{"id" => id}}} <- CommonAPI.unfavorite(ap_id_or_id, user), + %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "POST /api/v1/statuses/:id/pin" + def pin(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do + with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "POST /api/v1/statuses/:id/unpin" + def unpin(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do + with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "POST /api/v1/statuses/:id/bookmark" + def bookmark(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + %User{} = user <- User.get_cached_by_nickname(user.nickname), + true <- Visibility.visible_for_user?(activity, user), + {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "POST /api/v1/statuses/:id/unbookmark" + def unbookmark(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + %User{} = user <- User.get_cached_by_nickname(user.nickname), + true <- Visibility.visible_for_user?(activity, user), + {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "POST /api/v1/statuses/:id/mute" + def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id(id), + {:ok, activity} <- CommonAPI.add_mute(user, activity) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "POST /api/v1/statuses/:id/unmute" + def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id(id), + {:ok, activity} <- CommonAPI.remove_mute(user, activity) do + try_render(conn, "show.json", activity: activity, for: user, as: :activity) + end + end + + @doc "GET /api/v1/statuses/:id/card" + def card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do + with %Activity{} = activity <- Activity.get_by_id(status_id), + true <- Visibility.visible_for_user?(activity, user) do + data = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) + render(conn, "card.json", data) + else + _ -> render_error(conn, :not_found, "Record not found") + end + end + + @doc "GET /api/v1/statuses/:id/favourited_by" + def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, + %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do + users = + User + |> Ecto.Query.where([u], u.ap_id in ^likes) + |> Repo.all() + |> Enum.filter(&(not User.blocks?(user, &1))) + + conn + |> put_view(AccountView) + |> render("accounts.json", for: user, users: users, as: :user) + else + {:visible, false} -> {:error, :not_found} + _ -> json(conn, []) + end + end + + @doc "GET /api/v1/statuses/:id/reblogged_by" + def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, + %Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do + users = + User + |> Ecto.Query.where([u], u.ap_id in ^announces) + |> Repo.all() + |> Enum.filter(&(not User.blocks?(user, &1))) + + conn + |> put_view(AccountView) + |> render("accounts.json", for: user, users: users, as: :user) + else + {:visible, false} -> {:error, :not_found} + _ -> json(conn, []) + end + end + + @doc "GET /api/v1/statuses/:id/context" + def context(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Activity.get_by_id(id) do + activities = + ActivityPub.fetch_activities_for_context(activity.data["context"], %{ + "blocking_user" => user, + "user" => user, + "exclude_id" => activity.id + }) + + # TODO: Move to view + grouped_activities = Enum.group_by(activities, fn %{id: id} -> id < activity.id end) + + result = %{ + ancestors: + StatusView.render( + "index.json", + for: user, + activities: grouped_activities[true] || [], + as: :activity + ) + |> Enum.reverse(), + # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart + descendants: + StatusView.render( + "index.json", + for: user, + activities: grouped_activities[false] || [], + as: :activity + ) + |> Enum.reverse() + # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart + } + + json(conn, result) + end + end +end diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index 40acc07b3..4aeb79d81 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -24,7 +24,7 @@ def render("participation.json", %{participation: participation, for: user}) do activity = Activity.get_by_id_with_object(last_activity_id) - last_status = StatusView.render("status.json", %{activity: activity, for: user}) + last_status = StatusView.render("show.json", %{activity: activity, for: user}) # Conversations return all users except the current user. users = diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex index ec8eadcaa..05110a192 100644 --- a/lib/pleroma/web/mastodon_api/views/notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex @@ -39,19 +39,19 @@ def render("show.json", %{ "mention" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: activity, for: user}) + status: StatusView.render("show.json", %{activity: activity, for: user}) }) "favourite" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + status: StatusView.render("show.json", %{activity: parent_activity, for: user}) }) "reblog" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + status: StatusView.render("show.json", %{activity: parent_activity, for: user}) }) "follow" -> diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index ef796cddd..59bef30f2 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -73,17 +73,13 @@ defp reblogged?(activity, user) do def render("index.json", opts) do replied_to_activities = get_replied_to_activities(opts.activities) + opts = Map.put(opts, :replied_to_activities, replied_to_activities) - opts.activities - |> safe_render_many( - StatusView, - "status.json", - Map.put(opts, :replied_to_activities, replied_to_activities) - ) + safe_render_many(opts.activities, StatusView, "show.json", opts) end def render( - "status.json", + "show.json", %{activity: %{data: %{"type" => "Announce", "object" => _object}} = activity} = opts ) do user = get_user(activity.data["actor"]) @@ -96,7 +92,7 @@ def render( |> Activity.with_set_thread_muted_field(opts[:for]) |> Repo.one() - reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity)) + reblogged = render("show.json", Map.put(opts, :activity, reblogged_activity)) favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || []) @@ -144,7 +140,7 @@ def render( } end - def render("status.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do + def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do object = Object.normalize(activity) user = get_user(activity.data["actor"]) @@ -303,7 +299,7 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity } end - def render("status.json", _) do + def render("show.json", _) do nil end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 2575481ff..7a20b6d75 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -355,19 +355,19 @@ defmodule Pleroma.Web.Router do patch("/accounts/update_credentials", MastodonAPIController, :update_credentials) - post("/statuses", MastodonAPIController, :post_status) - delete("/statuses/:id", MastodonAPIController, :delete_status) + post("/statuses", StatusController, :create) + delete("/statuses/:id", StatusController, :delete) - post("/statuses/:id/reblog", MastodonAPIController, :reblog_status) - post("/statuses/:id/unreblog", MastodonAPIController, :unreblog_status) - post("/statuses/:id/favourite", MastodonAPIController, :fav_status) - post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status) - post("/statuses/:id/pin", MastodonAPIController, :pin_status) - post("/statuses/:id/unpin", MastodonAPIController, :unpin_status) - post("/statuses/:id/bookmark", MastodonAPIController, :bookmark_status) - post("/statuses/:id/unbookmark", MastodonAPIController, :unbookmark_status) - post("/statuses/:id/mute", MastodonAPIController, :mute_conversation) - post("/statuses/:id/unmute", MastodonAPIController, :unmute_conversation) + post("/statuses/:id/reblog", StatusController, :reblog) + post("/statuses/:id/unreblog", StatusController, :unreblog) + post("/statuses/:id/favourite", StatusController, :favourite) + post("/statuses/:id/unfavourite", StatusController, :unfavourite) + post("/statuses/:id/pin", StatusController, :pin) + post("/statuses/:id/unpin", StatusController, :unpin) + post("/statuses/:id/bookmark", StatusController, :bookmark) + post("/statuses/:id/unbookmark", StatusController, :unbookmark) + post("/statuses/:id/mute", StatusController, :mute_conversation) + post("/statuses/:id/unmute", StatusController, :unmute_conversation) put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status) delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status) @@ -448,10 +448,10 @@ defmodule Pleroma.Web.Router do get("/apps/verify_credentials", MastodonAPIController, :verify_app_credentials) get("/custom_emojis", MastodonAPIController, :custom_emojis) - get("/statuses/:id/card", MastodonAPIController, :status_card) + get("/statuses/:id/card", StatusController, :card) - get("/statuses/:id/favourited_by", MastodonAPIController, :favourited_by) - get("/statuses/:id/reblogged_by", MastodonAPIController, :reblogged_by) + get("/statuses/:id/favourited_by", StatusController, :favourited_by) + get("/statuses/:id/reblogged_by", StatusController, :reblogged_by) get("/trends", MastodonAPIController, :empty_array) @@ -470,9 +470,9 @@ defmodule Pleroma.Web.Router do get("/timelines/tag/:tag", TimelineController, :hashtag) get("/timelines/list/:list_id", TimelineController, :list) - get("/statuses", MastodonAPIController, :get_statuses) - get("/statuses/:id", MastodonAPIController, :get_status) - get("/statuses/:id/context", MastodonAPIController, :get_context) + get("/statuses", StatusController, :index) + get("/statuses/:id", StatusController, :show) + get("/statuses/:id/context", StatusController, :context) get("/polls/:id", MastodonAPIController, :get_poll) diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex index b13030fa0..a9f14d09a 100644 --- a/lib/pleroma/web/views/streamer_view.ex +++ b/lib/pleroma/web/views/streamer_view.ex @@ -16,7 +16,7 @@ def render("update.json", %Activity{} = activity, %User{} = user) do event: "update", payload: Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", + "show.json", activity: activity, for: user ) @@ -43,7 +43,7 @@ def render("update.json", %Activity{} = activity) do event: "update", payload: Pleroma.Web.MastodonAPI.StatusView.render( - "status.json", + "show.json", activity: activity ) |> Jason.encode!() diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index ed7ce8fe0..63fce07bb 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -68,7 +68,7 @@ test "receives well formatted events" do assert {:ok, json} = Jason.decode(json["payload"]) view_json = - Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: activity, for: nil) + Pleroma.Web.MastodonAPI.StatusView.render("show.json", activity: activity, for: nil) |> Jason.encode!() |> Jason.decode!() diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs index 40df01101..35b6947a0 100644 --- a/test/web/admin_api/views/report_view_test.exs +++ b/test/web/admin_api/views/report_view_test.exs @@ -61,7 +61,7 @@ test "includes reported statuses" do AccountView.render("account.json", %{user: other_user}), Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user}) ), - statuses: [StatusView.render("status.json", %{activity: activity})], + statuses: [StatusView.render("show.json", %{activity: activity})], state: "open", id: report_activity.id } diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs index 9231aaec8..86268fcfa 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -28,7 +28,7 @@ test "Mention notification" do pleroma: %{is_seen: false}, type: "mention", account: AccountView.render("account.json", %{user: user, for: mentioned_user}), - status: StatusView.render("status.json", %{activity: activity, for: mentioned_user}), + status: StatusView.render("show.json", %{activity: activity, for: mentioned_user}), created_at: Utils.to_masto_date(notification.inserted_at) } @@ -51,7 +51,7 @@ test "Favourite notification" do pleroma: %{is_seen: false}, type: "favourite", account: AccountView.render("account.json", %{user: another_user, for: user}), - status: StatusView.render("status.json", %{activity: create_activity, for: user}), + status: StatusView.render("show.json", %{activity: create_activity, for: user}), created_at: Utils.to_masto_date(notification.inserted_at) } @@ -73,7 +73,7 @@ test "Reblog notification" do pleroma: %{is_seen: false}, type: "reblog", account: AccountView.render("account.json", %{user: another_user, for: user}), - status: StatusView.render("status.json", %{activity: reblog_activity, for: user}), + status: StatusView.render("show.json", %{activity: reblog_activity, for: user}), created_at: Utils.to_masto_date(notification.inserted_at) } diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index 51f8434fa..c17d0ef95 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -29,7 +29,7 @@ test "returns the direct conversation id when given the `with_conversation_id` o {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) status = - StatusView.render("status.json", + StatusView.render("show.json", activity: activity, with_direct_conversation_id: true, for: user @@ -46,7 +46,7 @@ test "returns a temporary ap_id based user for activities missing db users" do Repo.delete(user) Cachex.clear(:user_cache) - %{account: ms_user} = StatusView.render("status.json", activity: activity) + %{account: ms_user} = StatusView.render("show.json", activity: activity) assert ms_user.acct == "erroruser@example.com" end @@ -63,7 +63,7 @@ test "tries to get a user by nickname if fetching by ap_id doesn't work" do Cachex.clear(:user_cache) - result = StatusView.render("status.json", activity: activity) + result = StatusView.render("show.json", activity: activity) assert result[:account][:id] == to_string(user.id) end @@ -81,7 +81,7 @@ test "a note with null content" do User.get_cached_by_ap_id(note.data["actor"]) - status = StatusView.render("status.json", %{activity: note}) + status = StatusView.render("show.json", %{activity: note}) assert status.content == "" end @@ -93,7 +93,7 @@ test "a note activity" do convo_id = Utils.context_to_conversation_id(object_data["context"]) - status = StatusView.render("status.json", %{activity: note}) + status = StatusView.render("show.json", %{activity: note}) created_at = (object_data["published"] || "") @@ -165,11 +165,11 @@ test "tells if the message is muted for some reason" do {:ok, user} = User.mute(user, other_user) {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) - status = StatusView.render("status.json", %{activity: activity}) + status = StatusView.render("show.json", %{activity: activity}) assert status.muted == false - status = StatusView.render("status.json", %{activity: activity, for: user}) + status = StatusView.render("show.json", %{activity: activity, for: user}) assert status.muted == true end @@ -181,13 +181,13 @@ test "tells if the message is thread muted" do {:ok, user} = User.mute(user, other_user) {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) - status = StatusView.render("status.json", %{activity: activity, for: user}) + status = StatusView.render("show.json", %{activity: activity, for: user}) assert status.pleroma.thread_muted == false {:ok, activity} = CommonAPI.add_mute(user, activity) - status = StatusView.render("status.json", %{activity: activity, for: user}) + status = StatusView.render("show.json", %{activity: activity, for: user}) assert status.pleroma.thread_muted == true end @@ -196,11 +196,11 @@ test "tells if the status is bookmarked" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{"status" => "Cute girls doing cute things"}) - status = StatusView.render("status.json", %{activity: activity}) + status = StatusView.render("show.json", %{activity: activity}) assert status.bookmarked == false - status = StatusView.render("status.json", %{activity: activity, for: user}) + status = StatusView.render("show.json", %{activity: activity, for: user}) assert status.bookmarked == false @@ -208,7 +208,7 @@ test "tells if the status is bookmarked" do activity = Activity.get_by_id_with_object(activity.id) - status = StatusView.render("status.json", %{activity: activity, for: user}) + status = StatusView.render("show.json", %{activity: activity, for: user}) assert status.bookmarked == true end @@ -220,7 +220,7 @@ test "a reply" do {:ok, activity} = CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id}) - status = StatusView.render("status.json", %{activity: activity}) + status = StatusView.render("show.json", %{activity: activity}) assert status.in_reply_to_id == to_string(note.id) @@ -237,7 +237,7 @@ test "contains mentions" do {:ok, [activity]} = OStatus.handle_incoming(incoming) - status = StatusView.render("status.json", %{activity: activity}) + status = StatusView.render("show.json", %{activity: activity}) assert status.mentions == Enum.map([user], fn u -> AccountView.render("mention.json", %{user: u}) end) @@ -263,7 +263,7 @@ test "create mentions from the 'to' field" do assert length(activity.recipients) == 3 - %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity}) + %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity}) assert length(mentions) == 1 assert mention.url == recipient_ap_id @@ -300,7 +300,7 @@ test "create mentions from the 'tag' field" do assert length(activity.recipients) == 3 - %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity}) + %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity}) assert length(mentions) == 1 assert mention.url == recipient.ap_id @@ -340,7 +340,7 @@ test "put the url advertised in the Activity in to the url attribute" do id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810" [activity] = Activity.search(nil, id) - status = StatusView.render("status.json", %{activity: activity}) + status = StatusView.render("show.json", %{activity: activity}) assert status.uri == id assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" @@ -352,7 +352,7 @@ test "a reblog" do {:ok, reblog, _} = CommonAPI.repeat(activity.id, user) - represented = StatusView.render("status.json", %{for: user, activity: reblog}) + represented = StatusView.render("show.json", %{for: user, activity: reblog}) assert represented[:id] == to_string(reblog.id) assert represented[:reblog][:id] == to_string(activity.id) @@ -369,7 +369,7 @@ test "a peertube video" do %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"]) - represented = StatusView.render("status.json", %{for: user, activity: activity}) + represented = StatusView.render("show.json", %{for: user, activity: activity}) assert represented[:id] == to_string(activity.id) assert length(represented[:media_attachments]) == 1 @@ -570,7 +570,7 @@ test "embeds a relationship in the account" do "status" => "drink more water" }) - result = StatusView.render("status.json", %{activity: activity, for: other_user}) + result = StatusView.render("show.json", %{activity: activity, for: other_user}) assert result[:account][:pleroma][:relationship] == AccountView.render("relationship.json", %{user: other_user, target: user}) @@ -587,7 +587,7 @@ test "embeds a relationship in the account in reposts" do {:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user) - result = StatusView.render("status.json", %{activity: activity, for: user}) + result = StatusView.render("show.json", %{activity: activity, for: user}) assert result[:account][:pleroma][:relationship] == AccountView.render("relationship.json", %{user: user, target: other_user}) @@ -604,7 +604,7 @@ test "visibility/list" do {:ok, activity} = CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"}) - status = StatusView.render("status.json", activity: activity) + status = StatusView.render("show.json", activity: activity) assert status.visibility == "list" end From 76b7e5cd5b34e68055bab7353cb845f3429d897f Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 26 Sep 2019 13:38:45 +0700 Subject: [PATCH 237/272] Move StatusController tests from MastodonAPIControllerTest to StatusControllerTest --- .../controllers/status_controller_test.exs | 1056 +++++++++++++++++ .../mastodon_api_controller_test.exs | 1027 ---------------- 2 files changed, 1056 insertions(+), 1027 deletions(-) create mode 100644 test/web/mastodon_api/controllers/status_controller_test.exs diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs new file mode 100644 index 000000000..f80ce7704 --- /dev/null +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -0,0 +1,1056 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Activity + alias Pleroma.ActivityExpiration + alias Pleroma.Config + alias Pleroma.Object + alias Pleroma.User + alias Pleroma.Web.CommonAPI + + import Pleroma.Factory + + describe "posting statuses" do + setup do + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + + [conn: conn] + end + + test "posting a status", %{conn: conn} do + idempotency_key = "Pikachu rocks!" + + conn_one = + conn + |> put_req_header("idempotency-key", idempotency_key) + |> post("/api/v1/statuses", %{ + "status" => "cofe", + "spoiler_text" => "2hu", + "sensitive" => "false" + }) + + {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key) + # Six hours + assert ttl > :timer.seconds(6 * 60 * 60 - 1) + + assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = + json_response(conn_one, 200) + + assert Activity.get_by_id(id) + + conn_two = + conn + |> put_req_header("idempotency-key", idempotency_key) + |> post("/api/v1/statuses", %{ + "status" => "cofe", + "spoiler_text" => "2hu", + "sensitive" => "false" + }) + + assert %{"id" => second_id} = json_response(conn_two, 200) + assert id == second_id + + conn_three = + conn + |> post("/api/v1/statuses", %{ + "status" => "cofe", + "spoiler_text" => "2hu", + "sensitive" => "false" + }) + + assert %{"id" => third_id} = json_response(conn_three, 200) + refute id == third_id + + # An activity that will expire: + # 2 hours + expires_in = 120 * 60 + + conn_four = + conn + |> post("api/v1/statuses", %{ + "status" => "oolong", + "expires_in" => expires_in + }) + + assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200) + assert activity = Activity.get_by_id(fourth_id) + assert expiration = ActivityExpiration.get_by_activity_id(fourth_id) + + estimated_expires_at = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(expires_in) + |> NaiveDateTime.truncate(:second) + + # This assert will fail if the test takes longer than a minute. I sure hope it never does: + assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60 + + assert fourth_response["pleroma"]["expires_at"] == + NaiveDateTime.to_iso8601(expiration.scheduled_at) + end + + test "replying to a status", %{conn: conn} do + user = insert(:user) + {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"}) + + conn = + conn + |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) + + assert %{"content" => "xD", "id" => id} = json_response(conn, 200) + + activity = Activity.get_by_id(id) + + assert activity.data["context"] == replied_to.data["context"] + assert Activity.get_in_reply_to_activity(activity).id == replied_to.id + end + + test "replying to a direct message with visibility other than direct", %{conn: conn} do + user = insert(:user) + {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"}) + + Enum.each(["public", "private", "unlisted"], fn visibility -> + conn = + conn + |> post("/api/v1/statuses", %{ + "status" => "@#{user.nickname} hey", + "in_reply_to_id" => replied_to.id, + "visibility" => visibility + }) + + assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"} + end) + end + + test "posting a status with an invalid in_reply_to_id", %{conn: conn} do + conn = + conn + |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""}) + + assert %{"content" => "xD", "id" => id} = json_response(conn, 200) + assert Activity.get_by_id(id) + end + + test "posting a sensitive status", %{conn: conn} do + conn = + conn + |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true}) + + assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200) + assert Activity.get_by_id(id) + end + + test "posting a fake status", %{conn: conn} do + real_conn = + conn + |> post("/api/v1/statuses", %{ + "status" => + "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it" + }) + + real_status = json_response(real_conn, 200) + + assert real_status + assert Object.get_by_ap_id(real_status["uri"]) + + real_status = + real_status + |> Map.put("id", nil) + |> Map.put("url", nil) + |> Map.put("uri", nil) + |> Map.put("created_at", nil) + |> Kernel.put_in(["pleroma", "conversation_id"], nil) + + fake_conn = + conn + |> post("/api/v1/statuses", %{ + "status" => + "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it", + "preview" => true + }) + + fake_status = json_response(fake_conn, 200) + + assert fake_status + refute Object.get_by_ap_id(fake_status["uri"]) + + fake_status = + fake_status + |> Map.put("id", nil) + |> Map.put("url", nil) + |> Map.put("uri", nil) + |> Map.put("created_at", nil) + |> Kernel.put_in(["pleroma", "conversation_id"], nil) + + assert real_status == fake_status + end + + test "posting a status with OGP link preview", %{conn: conn} do + Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + Config.put([:rich_media, :enabled], true) + + conn = + conn + |> post("/api/v1/statuses", %{ + "status" => "https://example.com/ogp" + }) + + assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200) + assert Activity.get_by_id(id) + end + + test "posting a direct status", %{conn: conn} do + user2 = insert(:user) + content = "direct cofe @#{user2.nickname}" + + conn = + conn + |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"}) + + assert %{"id" => id} = response = json_response(conn, 200) + assert response["visibility"] == "direct" + assert response["pleroma"]["direct_conversation_id"] + assert activity = Activity.get_by_id(id) + assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id] + assert activity.data["to"] == [user2.ap_id] + assert activity.data["cc"] == [] + end + end + + describe "posting polls" do + test "posting a poll", %{conn: conn} do + user = insert(:user) + time = NaiveDateTime.utc_now() + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "status" => "Who is the #bestgrill?", + "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420} + }) + + response = json_response(conn, 200) + + assert Enum.all?(response["poll"]["options"], fn %{"title" => title} -> + title in ["Rei", "Asuka", "Misato"] + end) + + assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430 + refute response["poll"]["expred"] + end + + test "option limit is enforced", %{conn: conn} do + user = insert(:user) + limit = Config.get([:instance, :poll_limits, :max_options]) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "status" => "desu~", + "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1} + }) + + %{"error" => error} = json_response(conn, 422) + assert error == "Poll can't contain more than #{limit} options" + end + + test "option character limit is enforced", %{conn: conn} do + user = insert(:user) + limit = Config.get([:instance, :poll_limits, :max_option_chars]) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "status" => "...", + "poll" => %{ + "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)], + "expires_in" => 1 + } + }) + + %{"error" => error} = json_response(conn, 422) + assert error == "Poll options cannot be longer than #{limit} characters each" + end + + test "minimal date limit is enforced", %{conn: conn} do + user = insert(:user) + limit = Config.get([:instance, :poll_limits, :min_expiration]) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "status" => "imagine arbitrary limits", + "poll" => %{ + "options" => ["this post was made by pleroma gang"], + "expires_in" => limit - 1 + } + }) + + %{"error" => error} = json_response(conn, 422) + assert error == "Expiration date is too soon" + end + + test "maximum date limit is enforced", %{conn: conn} do + user = insert(:user) + limit = Config.get([:instance, :poll_limits, :max_expiration]) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "status" => "imagine arbitrary limits", + "poll" => %{ + "options" => ["this post was made by pleroma gang"], + "expires_in" => limit + 1 + } + }) + + %{"error" => error} = json_response(conn, 422) + assert error == "Expiration date is too far in the future" + end + end + + test "get a status", %{conn: conn} do + activity = insert(:note_activity) + + conn = + conn + |> get("/api/v1/statuses/#{activity.id}") + + assert %{"id" => id} = json_response(conn, 200) + assert id == to_string(activity.id) + end + + test "get statuses by IDs", %{conn: conn} do + %{id: id1} = insert(:note_activity) + %{id: id2} = insert(:note_activity) + + query_string = "ids[]=#{id1}&ids[]=#{id2}" + conn = get(conn, "/api/v1/statuses/?#{query_string}") + + assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"]) + end + + describe "deleting a status" do + test "when you created it", %{conn: conn} do + activity = insert(:note_activity) + author = User.get_cached_by_ap_id(activity.data["actor"]) + + conn = + conn + |> assign(:user, author) + |> delete("/api/v1/statuses/#{activity.id}") + + assert %{} = json_response(conn, 200) + + refute Activity.get_by_id(activity.id) + end + + test "when you didn't create it", %{conn: conn} do + activity = insert(:note_activity) + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> delete("/api/v1/statuses/#{activity.id}") + + assert %{"error" => _} = json_response(conn, 403) + + assert Activity.get_by_id(activity.id) == activity + end + + test "when you're an admin or moderator", %{conn: conn} do + activity1 = insert(:note_activity) + activity2 = insert(:note_activity) + admin = insert(:user, info: %{is_admin: true}) + moderator = insert(:user, info: %{is_moderator: true}) + + res_conn = + conn + |> assign(:user, admin) + |> delete("/api/v1/statuses/#{activity1.id}") + + assert %{} = json_response(res_conn, 200) + + res_conn = + conn + |> assign(:user, moderator) + |> delete("/api/v1/statuses/#{activity2.id}") + + assert %{} = json_response(res_conn, 200) + + refute Activity.get_by_id(activity1.id) + refute Activity.get_by_id(activity2.id) + end + end + + describe "reblogging" do + test "reblogs and returns the reblogged status", %{conn: conn} do + activity = insert(:note_activity) + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/reblog") + + assert %{ + "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, + "reblogged" => true + } = json_response(conn, 200) + + assert to_string(activity.id) == id + end + + test "reblogged status for another user", %{conn: conn} do + activity = insert(:note_activity) + user1 = insert(:user) + user2 = insert(:user) + user3 = insert(:user) + CommonAPI.favorite(activity.id, user2) + {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) + {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) + {:ok, _, _object} = CommonAPI.repeat(activity.id, user2) + + conn_res = + conn + |> assign(:user, user3) + |> get("/api/v1/statuses/#{reblog_activity1.id}") + + assert %{ + "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, + "reblogged" => false, + "favourited" => false, + "bookmarked" => false + } = json_response(conn_res, 200) + + conn_res = + conn + |> assign(:user, user2) + |> get("/api/v1/statuses/#{reblog_activity1.id}") + + assert %{ + "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2}, + "reblogged" => true, + "favourited" => true, + "bookmarked" => true + } = json_response(conn_res, 200) + + assert to_string(activity.id) == id + end + + test "returns 400 error when activity is not exist", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/foo/reblog") + + assert json_response(conn, 400) == %{"error" => "Could not repeat"} + end + end + + describe "unreblogging" do + test "unreblogs and returns the unreblogged status", %{conn: conn} do + activity = insert(:note_activity) + user = insert(:user) + + {:ok, _, _} = CommonAPI.repeat(activity.id, user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/unreblog") + + assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200) + + assert to_string(activity.id) == id + end + + test "returns 400 error when activity is not exist", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/foo/unreblog") + + assert json_response(conn, 400) == %{"error" => "Could not unrepeat"} + end + end + + describe "favoriting" do + test "favs a status and returns it", %{conn: conn} do + activity = insert(:note_activity) + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/favourite") + + assert %{"id" => id, "favourites_count" => 1, "favourited" => true} = + json_response(conn, 200) + + assert to_string(activity.id) == id + end + + test "returns 400 error for a wrong id", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/1/favourite") + + assert json_response(conn, 400) == %{"error" => "Could not favorite"} + end + end + + describe "unfavoriting" do + test "unfavorites a status and returns it", %{conn: conn} do + activity = insert(:note_activity) + user = insert(:user) + + {:ok, _, _} = CommonAPI.favorite(activity.id, user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/unfavourite") + + assert %{"id" => id, "favourites_count" => 0, "favourited" => false} = + json_response(conn, 200) + + assert to_string(activity.id) == id + end + + test "returns 400 error for a wrong id", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/1/unfavourite") + + assert json_response(conn, 400) == %{"error" => "Could not unfavorite"} + end + end + + describe "pinned statuses" do + setup do + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"}) + + [user: user, activity: activity] + end + + clear_config([:instance, :max_pinned_statuses]) do + Config.put([:instance, :max_pinned_statuses], 1) + end + + test "pin status", %{conn: conn, user: user, activity: activity} do + id_str = to_string(activity.id) + + assert %{"id" => ^id_str, "pinned" => true} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/pin") + |> json_response(200) + + assert [%{"id" => ^id_str, "pinned" => true}] = + conn + |> assign(:user, user) + |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") + |> json_response(200) + end + + test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do + {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{dm.id}/pin") + + assert json_response(conn, 400) == %{"error" => "Could not pin"} + end + + test "unpin status", %{conn: conn, user: user, activity: activity} do + {:ok, _} = CommonAPI.pin(activity.id, user) + + id_str = to_string(activity.id) + user = refresh_record(user) + + assert %{"id" => ^id_str, "pinned" => false} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/unpin") + |> json_response(200) + + assert [] = + conn + |> assign(:user, user) + |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") + |> json_response(200) + end + + test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/1/unpin") + + assert json_response(conn, 400) == %{"error" => "Could not unpin"} + end + + test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do + {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"}) + + id_str_one = to_string(activity_one.id) + + assert %{"id" => ^id_str_one, "pinned" => true} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{id_str_one}/pin") + |> json_response(200) + + user = refresh_record(user) + + assert %{"error" => "You have already pinned the maximum number of statuses"} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity_two.id}/pin") + |> json_response(400) + end + end + + describe "cards" do + setup do + Config.put([:rich_media, :enabled], true) + + user = insert(:user) + %{user: user} + end + + test "returns rich-media card", %{conn: conn, user: user} do + Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"}) + + card_data = %{ + "image" => "http://ia.media-imdb.com/images/rock.jpg", + "provider_name" => "example.com", + "provider_url" => "https://example.com", + "title" => "The Rock", + "type" => "link", + "url" => "https://example.com/ogp", + "description" => + "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.", + "pleroma" => %{ + "opengraph" => %{ + "image" => "http://ia.media-imdb.com/images/rock.jpg", + "title" => "The Rock", + "type" => "video.movie", + "url" => "https://example.com/ogp", + "description" => + "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer." + } + } + } + + response = + conn + |> get("/api/v1/statuses/#{activity.id}/card") + |> json_response(200) + + assert response == card_data + + # works with private posts + {:ok, activity} = + CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"}) + + response_two = + conn + |> assign(:user, user) + |> get("/api/v1/statuses/#{activity.id}/card") + |> json_response(200) + + assert response_two == card_data + end + + test "replaces missing description with an empty string", %{conn: conn, user: user} do + Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"}) + + response = + conn + |> get("/api/v1/statuses/#{activity.id}/card") + |> json_response(:ok) + + assert response == %{ + "type" => "link", + "title" => "Pleroma", + "description" => "", + "image" => nil, + "provider_name" => "example.com", + "provider_url" => "https://example.com", + "url" => "https://example.com/ogp-missing-data", + "pleroma" => %{ + "opengraph" => %{ + "title" => "Pleroma", + "type" => "website", + "url" => "https://example.com/ogp-missing-data" + } + } + } + end + end + + test "bookmarks" do + user = insert(:user) + for_user = insert(:user) + + {:ok, activity1} = + CommonAPI.post(user, %{ + "status" => "heweoo?" + }) + + {:ok, activity2} = + CommonAPI.post(user, %{ + "status" => "heweoo!" + }) + + response1 = + build_conn() + |> assign(:user, for_user) + |> post("/api/v1/statuses/#{activity1.id}/bookmark") + + assert json_response(response1, 200)["bookmarked"] == true + + response2 = + build_conn() + |> assign(:user, for_user) + |> post("/api/v1/statuses/#{activity2.id}/bookmark") + + assert json_response(response2, 200)["bookmarked"] == true + + bookmarks = + build_conn() + |> assign(:user, for_user) + |> get("/api/v1/bookmarks") + + assert [json_response(response2, 200), json_response(response1, 200)] == + json_response(bookmarks, 200) + + response1 = + build_conn() + |> assign(:user, for_user) + |> post("/api/v1/statuses/#{activity1.id}/unbookmark") + + assert json_response(response1, 200)["bookmarked"] == false + + bookmarks = + build_conn() + |> assign(:user, for_user) + |> get("/api/v1/bookmarks") + + assert [json_response(response2, 200)] == json_response(bookmarks, 200) + end + + describe "conversation muting" do + setup do + post_user = insert(:user) + user = insert(:user) + + {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"}) + + [user: user, activity: activity] + end + + test "mute conversation", %{conn: conn, user: user, activity: activity} do + id_str = to_string(activity.id) + + assert %{"id" => ^id_str, "muted" => true} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/mute") + |> json_response(200) + end + + test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do + {:ok, _} = CommonAPI.add_mute(user, activity) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/mute") + + assert json_response(conn, 400) == %{"error" => "conversation is already muted"} + end + + test "unmute conversation", %{conn: conn, user: user, activity: activity} do + {:ok, _} = CommonAPI.add_mute(user, activity) + + id_str = to_string(activity.id) + user = refresh_record(user) + + assert %{"id" => ^id_str, "muted" => false} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/unmute") + |> json_response(200) + end + end + + test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do + user1 = insert(:user) + user2 = insert(:user) + user3 = insert(:user) + + {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"}) + + # Reply to status from another user + conn1 = + conn + |> assign(:user, user2) + |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) + + assert %{"content" => "xD", "id" => id} = json_response(conn1, 200) + + activity = Activity.get_by_id_with_object(id) + + assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"] + assert Activity.get_in_reply_to_activity(activity).id == replied_to.id + + # Reblog from the third user + conn2 = + conn + |> assign(:user, user3) + |> post("/api/v1/statuses/#{activity.id}/reblog") + + assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = + json_response(conn2, 200) + + assert to_string(activity.id) == id + + # Getting third user status + conn3 = + conn + |> assign(:user, user3) + |> get("api/v1/timelines/home") + + [reblogged_activity] = json_response(conn3, 200) + + assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id + + replied_to_user = User.get_by_ap_id(replied_to.data["actor"]) + assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id + end + + describe "GET /api/v1/statuses/:id/favourited_by" do + setup do + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) + + conn = + build_conn() + |> assign(:user, user) + + [conn: conn, activity: activity, user: user] + end + + test "returns users who have favorited the status", %{conn: conn, activity: activity} do + other_user = insert(:user) + {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + + response = + conn + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(:ok) + + [%{"id" => id}] = response + + assert id == other_user.id + end + + test "returns empty array when status has not been favorited yet", %{ + conn: conn, + activity: activity + } do + response = + conn + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(:ok) + + assert Enum.empty?(response) + end + + test "does not return users who have favorited the status but are blocked", %{ + conn: %{assigns: %{user: user}} = conn, + activity: activity + } do + other_user = insert(:user) + {:ok, user} = User.block(user, other_user) + + {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + + response = + conn + |> assign(:user, user) + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(:ok) + + assert Enum.empty?(response) + end + + test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do + other_user = insert(:user) + {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + + response = + conn + |> assign(:user, nil) + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(:ok) + + [%{"id" => id}] = response + assert id == other_user.id + end + + test "requires authentification for private posts", %{conn: conn, user: user} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "@#{other_user.nickname} wanna get some #cofe together?", + "visibility" => "direct" + }) + + {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + + conn + |> assign(:user, nil) + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(404) + + response = + build_conn() + |> assign(:user, other_user) + |> get("/api/v1/statuses/#{activity.id}/favourited_by") + |> json_response(200) + + [%{"id" => id}] = response + assert id == other_user.id + end + end + + describe "GET /api/v1/statuses/:id/reblogged_by" do + setup do + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) + + conn = + build_conn() + |> assign(:user, user) + + [conn: conn, activity: activity, user: user] + end + + test "returns users who have reblogged the status", %{conn: conn, activity: activity} do + other_user = insert(:user) + {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) + + response = + conn + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(:ok) + + [%{"id" => id}] = response + + assert id == other_user.id + end + + test "returns empty array when status has not been reblogged yet", %{ + conn: conn, + activity: activity + } do + response = + conn + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(:ok) + + assert Enum.empty?(response) + end + + test "does not return users who have reblogged the status but are blocked", %{ + conn: %{assigns: %{user: user}} = conn, + activity: activity + } do + other_user = insert(:user) + {:ok, user} = User.block(user, other_user) + + {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) + + response = + conn + |> assign(:user, user) + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(:ok) + + assert Enum.empty?(response) + end + + test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do + other_user = insert(:user) + {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) + + response = + conn + |> assign(:user, nil) + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(:ok) + + [%{"id" => id}] = response + assert id == other_user.id + end + + test "requires authentification for private posts", %{conn: conn, user: user} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "@#{other_user.nickname} wanna get some #cofe together?", + "visibility" => "direct" + }) + + conn + |> assign(:user, nil) + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(404) + + response = + build_conn() + |> assign(:user, other_user) + |> get("/api/v1/statuses/#{activity.id}/reblogged_by") + |> json_response(200) + + assert [] == response + end + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 7f7a89516..6435ad7a9 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -7,7 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Ecto.Changeset alias Pleroma.Activity - alias Pleroma.ActivityExpiration alias Pleroma.Config alias Pleroma.Notification alias Pleroma.Object @@ -37,312 +36,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do clear_config([:instance, :public]) clear_config([:rich_media, :enabled]) - describe "posting statuses" do - setup do - user = insert(:user) - - conn = - build_conn() - |> assign(:user, user) - - [conn: conn] - end - - test "posting a status", %{conn: conn} do - idempotency_key = "Pikachu rocks!" - - conn_one = - conn - |> put_req_header("idempotency-key", idempotency_key) - |> post("/api/v1/statuses", %{ - "status" => "cofe", - "spoiler_text" => "2hu", - "sensitive" => "false" - }) - - {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key) - # Six hours - assert ttl > :timer.seconds(6 * 60 * 60 - 1) - - assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = - json_response(conn_one, 200) - - assert Activity.get_by_id(id) - - conn_two = - conn - |> put_req_header("idempotency-key", idempotency_key) - |> post("/api/v1/statuses", %{ - "status" => "cofe", - "spoiler_text" => "2hu", - "sensitive" => "false" - }) - - assert %{"id" => second_id} = json_response(conn_two, 200) - assert id == second_id - - conn_three = - conn - |> post("/api/v1/statuses", %{ - "status" => "cofe", - "spoiler_text" => "2hu", - "sensitive" => "false" - }) - - assert %{"id" => third_id} = json_response(conn_three, 200) - refute id == third_id - - # An activity that will expire: - # 2 hours - expires_in = 120 * 60 - - conn_four = - conn - |> post("api/v1/statuses", %{ - "status" => "oolong", - "expires_in" => expires_in - }) - - assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200) - assert activity = Activity.get_by_id(fourth_id) - assert expiration = ActivityExpiration.get_by_activity_id(fourth_id) - - estimated_expires_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(expires_in) - |> NaiveDateTime.truncate(:second) - - # This assert will fail if the test takes longer than a minute. I sure hope it never does: - assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60 - - assert fourth_response["pleroma"]["expires_at"] == - NaiveDateTime.to_iso8601(expiration.scheduled_at) - end - - test "replying to a status", %{conn: conn} do - user = insert(:user) - {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"}) - - conn = - conn - |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) - - assert %{"content" => "xD", "id" => id} = json_response(conn, 200) - - activity = Activity.get_by_id(id) - - assert activity.data["context"] == replied_to.data["context"] - assert Activity.get_in_reply_to_activity(activity).id == replied_to.id - end - - test "replying to a direct message with visibility other than direct", %{conn: conn} do - user = insert(:user) - {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"}) - - Enum.each(["public", "private", "unlisted"], fn visibility -> - conn = - conn - |> post("/api/v1/statuses", %{ - "status" => "@#{user.nickname} hey", - "in_reply_to_id" => replied_to.id, - "visibility" => visibility - }) - - assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"} - end) - end - - test "posting a status with an invalid in_reply_to_id", %{conn: conn} do - conn = - conn - |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""}) - - assert %{"content" => "xD", "id" => id} = json_response(conn, 200) - assert Activity.get_by_id(id) - end - - test "posting a sensitive status", %{conn: conn} do - conn = - conn - |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true}) - - assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200) - assert Activity.get_by_id(id) - end - - test "posting a fake status", %{conn: conn} do - real_conn = - conn - |> post("/api/v1/statuses", %{ - "status" => - "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it" - }) - - real_status = json_response(real_conn, 200) - - assert real_status - assert Object.get_by_ap_id(real_status["uri"]) - - real_status = - real_status - |> Map.put("id", nil) - |> Map.put("url", nil) - |> Map.put("uri", nil) - |> Map.put("created_at", nil) - |> Kernel.put_in(["pleroma", "conversation_id"], nil) - - fake_conn = - conn - |> post("/api/v1/statuses", %{ - "status" => - "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it", - "preview" => true - }) - - fake_status = json_response(fake_conn, 200) - - assert fake_status - refute Object.get_by_ap_id(fake_status["uri"]) - - fake_status = - fake_status - |> Map.put("id", nil) - |> Map.put("url", nil) - |> Map.put("uri", nil) - |> Map.put("created_at", nil) - |> Kernel.put_in(["pleroma", "conversation_id"], nil) - - assert real_status == fake_status - end - - test "posting a status with OGP link preview", %{conn: conn} do - Config.put([:rich_media, :enabled], true) - - conn = - conn - |> post("/api/v1/statuses", %{ - "status" => "https://example.com/ogp" - }) - - assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200) - assert Activity.get_by_id(id) - end - - test "posting a direct status", %{conn: conn} do - user2 = insert(:user) - content = "direct cofe @#{user2.nickname}" - - conn = - conn - |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"}) - - assert %{"id" => id} = response = json_response(conn, 200) - assert response["visibility"] == "direct" - assert response["pleroma"]["direct_conversation_id"] - assert activity = Activity.get_by_id(id) - assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id] - assert activity.data["to"] == [user2.ap_id] - assert activity.data["cc"] == [] - end - end - - describe "posting polls" do - test "posting a poll", %{conn: conn} do - user = insert(:user) - time = NaiveDateTime.utc_now() - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "status" => "Who is the #bestgrill?", - "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420} - }) - - response = json_response(conn, 200) - - assert Enum.all?(response["poll"]["options"], fn %{"title" => title} -> - title in ["Rei", "Asuka", "Misato"] - end) - - assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430 - refute response["poll"]["expred"] - end - - test "option limit is enforced", %{conn: conn} do - user = insert(:user) - limit = Config.get([:instance, :poll_limits, :max_options]) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "status" => "desu~", - "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1} - }) - - %{"error" => error} = json_response(conn, 422) - assert error == "Poll can't contain more than #{limit} options" - end - - test "option character limit is enforced", %{conn: conn} do - user = insert(:user) - limit = Config.get([:instance, :poll_limits, :max_option_chars]) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "status" => "...", - "poll" => %{ - "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)], - "expires_in" => 1 - } - }) - - %{"error" => error} = json_response(conn, 422) - assert error == "Poll options cannot be longer than #{limit} characters each" - end - - test "minimal date limit is enforced", %{conn: conn} do - user = insert(:user) - limit = Config.get([:instance, :poll_limits, :min_expiration]) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "status" => "imagine arbitrary limits", - "poll" => %{ - "options" => ["this post was made by pleroma gang"], - "expires_in" => limit - 1 - } - }) - - %{"error" => error} = json_response(conn, 422) - assert error == "Expiration date is too soon" - end - - test "maximum date limit is enforced", %{conn: conn} do - user = insert(:user) - limit = Config.get([:instance, :poll_limits, :max_expiration]) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "status" => "imagine arbitrary limits", - "poll" => %{ - "options" => ["this post was made by pleroma gang"], - "expires_in" => limit + 1 - } - }) - - %{"error" => error} = json_response(conn, 422) - assert error == "Expiration date is too far in the future" - end - end - test "Conversations", %{conn: conn} do user_one = insert(:user) user_two = insert(:user) @@ -575,81 +268,6 @@ test "creates an oauth app", %{conn: conn} do assert expected == json_response(conn, 200) end - test "get a status", %{conn: conn} do - activity = insert(:note_activity) - - conn = - conn - |> get("/api/v1/statuses/#{activity.id}") - - assert %{"id" => id} = json_response(conn, 200) - assert id == to_string(activity.id) - end - - test "get statuses by IDs", %{conn: conn} do - %{id: id1} = insert(:note_activity) - %{id: id2} = insert(:note_activity) - - query_string = "ids[]=#{id1}&ids[]=#{id2}" - conn = get(conn, "/api/v1/statuses/?#{query_string}") - - assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"]) - end - - describe "deleting a status" do - test "when you created it", %{conn: conn} do - activity = insert(:note_activity) - author = User.get_cached_by_ap_id(activity.data["actor"]) - - conn = - conn - |> assign(:user, author) - |> delete("/api/v1/statuses/#{activity.id}") - - assert %{} = json_response(conn, 200) - - refute Activity.get_by_id(activity.id) - end - - test "when you didn't create it", %{conn: conn} do - activity = insert(:note_activity) - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> delete("/api/v1/statuses/#{activity.id}") - - assert %{"error" => _} = json_response(conn, 403) - - assert Activity.get_by_id(activity.id) == activity - end - - test "when you're an admin or moderator", %{conn: conn} do - activity1 = insert(:note_activity) - activity2 = insert(:note_activity) - admin = insert(:user, info: %{is_admin: true}) - moderator = insert(:user, info: %{is_moderator: true}) - - res_conn = - conn - |> assign(:user, admin) - |> delete("/api/v1/statuses/#{activity1.id}") - - assert %{} = json_response(res_conn, 200) - - res_conn = - conn - |> assign(:user, moderator) - |> delete("/api/v1/statuses/#{activity2.id}") - - assert %{} = json_response(res_conn, 200) - - refute Activity.get_by_id(activity1.id) - refute Activity.get_by_id(activity2.id) - end - end - describe "filters" do test "creating a filter", %{conn: conn} do user = insert(:user) @@ -778,160 +396,6 @@ test "delete a filter", %{conn: conn} do end end - describe "reblogging" do - test "reblogs and returns the reblogged status", %{conn: conn} do - activity = insert(:note_activity) - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/reblog") - - assert %{ - "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, - "reblogged" => true - } = json_response(conn, 200) - - assert to_string(activity.id) == id - end - - test "reblogged status for another user", %{conn: conn} do - activity = insert(:note_activity) - user1 = insert(:user) - user2 = insert(:user) - user3 = insert(:user) - CommonAPI.favorite(activity.id, user2) - {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) - {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) - {:ok, _, _object} = CommonAPI.repeat(activity.id, user2) - - conn_res = - conn - |> assign(:user, user3) - |> get("/api/v1/statuses/#{reblog_activity1.id}") - - assert %{ - "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, - "reblogged" => false, - "favourited" => false, - "bookmarked" => false - } = json_response(conn_res, 200) - - conn_res = - conn - |> assign(:user, user2) - |> get("/api/v1/statuses/#{reblog_activity1.id}") - - assert %{ - "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2}, - "reblogged" => true, - "favourited" => true, - "bookmarked" => true - } = json_response(conn_res, 200) - - assert to_string(activity.id) == id - end - - test "returns 400 error when activity is not exist", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/foo/reblog") - - assert json_response(conn, 400) == %{"error" => "Could not repeat"} - end - end - - describe "unreblogging" do - test "unreblogs and returns the unreblogged status", %{conn: conn} do - activity = insert(:note_activity) - user = insert(:user) - - {:ok, _, _} = CommonAPI.repeat(activity.id, user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/unreblog") - - assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200) - - assert to_string(activity.id) == id - end - - test "returns 400 error when activity is not exist", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/foo/unreblog") - - assert json_response(conn, 400) == %{"error" => "Could not unrepeat"} - end - end - - describe "favoriting" do - test "favs a status and returns it", %{conn: conn} do - activity = insert(:note_activity) - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/favourite") - - assert %{"id" => id, "favourites_count" => 1, "favourited" => true} = - json_response(conn, 200) - - assert to_string(activity.id) == id - end - - test "returns 400 error for a wrong id", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/1/favourite") - - assert json_response(conn, 400) == %{"error" => "Could not favorite"} - end - end - - describe "unfavoriting" do - test "unfavorites a status and returns it", %{conn: conn} do - activity = insert(:note_activity) - user = insert(:user) - - {:ok, _, _} = CommonAPI.favorite(activity.id, user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/unfavourite") - - assert %{"id" => id, "favourites_count" => 0, "favourited" => false} = - json_response(conn, 200) - - assert to_string(activity.id) == id - end - - test "returns 400 error for a wrong id", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/1/unfavourite") - - assert json_response(conn, 400) == %{"error" => "Could not unfavorite"} - end - end - describe "user timelines" do test "gets a users statuses", %{conn: conn} do user_one = insert(:user) @@ -2098,10 +1562,6 @@ test "put settings", %{conn: conn} do [user: user, activity: activity] end - clear_config([:instance, :max_pinned_statuses]) do - Config.put([:instance, :max_pinned_statuses], 1) - end - test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do {:ok, _} = CommonAPI.pin(activity.id, user) @@ -2115,257 +1575,6 @@ test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do assert [%{"id" => ^id_str, "pinned" => true}] = result end - - test "pin status", %{conn: conn, user: user, activity: activity} do - id_str = to_string(activity.id) - - assert %{"id" => ^id_str, "pinned" => true} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/pin") - |> json_response(200) - - assert [%{"id" => ^id_str, "pinned" => true}] = - conn - |> assign(:user, user) - |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") - |> json_response(200) - end - - test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do - {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{dm.id}/pin") - - assert json_response(conn, 400) == %{"error" => "Could not pin"} - end - - test "unpin status", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.pin(activity.id, user) - - id_str = to_string(activity.id) - user = refresh_record(user) - - assert %{"id" => ^id_str, "pinned" => false} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/unpin") - |> json_response(200) - - assert [] = - conn - |> assign(:user, user) - |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") - |> json_response(200) - end - - test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/1/unpin") - - assert json_response(conn, 400) == %{"error" => "Could not unpin"} - end - - test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do - {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"}) - - id_str_one = to_string(activity_one.id) - - assert %{"id" => ^id_str_one, "pinned" => true} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{id_str_one}/pin") - |> json_response(200) - - user = refresh_record(user) - - assert %{"error" => "You have already pinned the maximum number of statuses"} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity_two.id}/pin") - |> json_response(400) - end - end - - describe "cards" do - setup do - Config.put([:rich_media, :enabled], true) - - user = insert(:user) - %{user: user} - end - - test "returns rich-media card", %{conn: conn, user: user} do - {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"}) - - card_data = %{ - "image" => "http://ia.media-imdb.com/images/rock.jpg", - "provider_name" => "example.com", - "provider_url" => "https://example.com", - "title" => "The Rock", - "type" => "link", - "url" => "https://example.com/ogp", - "description" => - "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.", - "pleroma" => %{ - "opengraph" => %{ - "image" => "http://ia.media-imdb.com/images/rock.jpg", - "title" => "The Rock", - "type" => "video.movie", - "url" => "https://example.com/ogp", - "description" => - "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer." - } - } - } - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/card") - |> json_response(200) - - assert response == card_data - - # works with private posts - {:ok, activity} = - CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"}) - - response_two = - conn - |> assign(:user, user) - |> get("/api/v1/statuses/#{activity.id}/card") - |> json_response(200) - - assert response_two == card_data - end - - test "replaces missing description with an empty string", %{conn: conn, user: user} do - {:ok, activity} = - CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"}) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/card") - |> json_response(:ok) - - assert response == %{ - "type" => "link", - "title" => "Pleroma", - "description" => "", - "image" => nil, - "provider_name" => "example.com", - "provider_url" => "https://example.com", - "url" => "https://example.com/ogp-missing-data", - "pleroma" => %{ - "opengraph" => %{ - "title" => "Pleroma", - "type" => "website", - "url" => "https://example.com/ogp-missing-data" - } - } - } - end - end - - test "bookmarks" do - user = insert(:user) - for_user = insert(:user) - - {:ok, activity1} = - CommonAPI.post(user, %{ - "status" => "heweoo?" - }) - - {:ok, activity2} = - CommonAPI.post(user, %{ - "status" => "heweoo!" - }) - - response1 = - build_conn() - |> assign(:user, for_user) - |> post("/api/v1/statuses/#{activity1.id}/bookmark") - - assert json_response(response1, 200)["bookmarked"] == true - - response2 = - build_conn() - |> assign(:user, for_user) - |> post("/api/v1/statuses/#{activity2.id}/bookmark") - - assert json_response(response2, 200)["bookmarked"] == true - - bookmarks = - build_conn() - |> assign(:user, for_user) - |> get("/api/v1/bookmarks") - - assert [json_response(response2, 200), json_response(response1, 200)] == - json_response(bookmarks, 200) - - response1 = - build_conn() - |> assign(:user, for_user) - |> post("/api/v1/statuses/#{activity1.id}/unbookmark") - - assert json_response(response1, 200)["bookmarked"] == false - - bookmarks = - build_conn() - |> assign(:user, for_user) - |> get("/api/v1/bookmarks") - - assert [json_response(response2, 200)] == json_response(bookmarks, 200) - end - - describe "conversation muting" do - setup do - post_user = insert(:user) - user = insert(:user) - - {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"}) - - [user: user, activity: activity] - end - - test "mute conversation", %{conn: conn, user: user, activity: activity} do - id_str = to_string(activity.id) - - assert %{"id" => ^id_str, "muted" => true} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/mute") - |> json_response(200) - end - - test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/mute") - - assert json_response(conn, 400) == %{"error" => "conversation is already muted"} - end - - test "unmute conversation", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) - - id_str = to_string(activity.id) - user = refresh_record(user) - - assert %{"id" => ^id_str, "muted" => false} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/unmute") - |> json_response(200) - end end describe "reports" do @@ -2811,51 +2020,6 @@ test "deletes a scheduled activity", %{conn: conn} do end end - test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do - user1 = insert(:user) - user2 = insert(:user) - user3 = insert(:user) - - {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"}) - - # Reply to status from another user - conn1 = - conn - |> assign(:user, user2) - |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) - - assert %{"content" => "xD", "id" => id} = json_response(conn1, 200) - - activity = Activity.get_by_id_with_object(id) - - assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"] - assert Activity.get_in_reply_to_activity(activity).id == replied_to.id - - # Reblog from the third user - conn2 = - conn - |> assign(:user, user3) - |> post("/api/v1/statuses/#{activity.id}/reblog") - - assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = - json_response(conn2, 200) - - assert to_string(activity.id) == id - - # Getting third user status - conn3 = - conn - |> assign(:user, user3) - |> get("api/v1/timelines/home") - - [reblogged_activity] = json_response(conn3, 200) - - assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id - - replied_to_user = User.get_by_ap_id(replied_to.data["actor"]) - assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id - end - describe "create account by app" do test "Account registration via Application", %{conn: conn} do conn = @@ -3135,197 +2299,6 @@ test "returns 404 when poll is private and not available for user", %{conn: conn end end - describe "GET /api/v1/statuses/:id/favourited_by" do - setup do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) - - conn = - build_conn() - |> assign(:user, user) - - [conn: conn, activity: activity, user: user] - end - - test "returns users who have favorited the status", %{conn: conn, activity: activity} do - other_user = insert(:user) - {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response(:ok) - - [%{"id" => id}] = response - - assert id == other_user.id - end - - test "returns empty array when status has not been favorited yet", %{ - conn: conn, - activity: activity - } do - response = - conn - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response(:ok) - - assert Enum.empty?(response) - end - - test "does not return users who have favorited the status but are blocked", %{ - conn: %{assigns: %{user: user}} = conn, - activity: activity - } do - other_user = insert(:user) - {:ok, user} = User.block(user, other_user) - - {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) - - response = - conn - |> assign(:user, user) - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response(:ok) - - assert Enum.empty?(response) - end - - test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do - other_user = insert(:user) - {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) - - response = - conn - |> assign(:user, nil) - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response(:ok) - - [%{"id" => id}] = response - assert id == other_user.id - end - - test "requires authentification for private posts", %{conn: conn, user: user} do - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - "status" => "@#{other_user.nickname} wanna get some #cofe together?", - "visibility" => "direct" - }) - - {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) - - conn - |> assign(:user, nil) - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response(404) - - response = - build_conn() - |> assign(:user, other_user) - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response(200) - - [%{"id" => id}] = response - assert id == other_user.id - end - end - - describe "GET /api/v1/statuses/:id/reblogged_by" do - setup do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) - - conn = - build_conn() - |> assign(:user, user) - - [conn: conn, activity: activity, user: user] - end - - test "returns users who have reblogged the status", %{conn: conn, activity: activity} do - other_user = insert(:user) - {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response(:ok) - - [%{"id" => id}] = response - - assert id == other_user.id - end - - test "returns empty array when status has not been reblogged yet", %{ - conn: conn, - activity: activity - } do - response = - conn - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response(:ok) - - assert Enum.empty?(response) - end - - test "does not return users who have reblogged the status but are blocked", %{ - conn: %{assigns: %{user: user}} = conn, - activity: activity - } do - other_user = insert(:user) - {:ok, user} = User.block(user, other_user) - - {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) - - response = - conn - |> assign(:user, user) - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response(:ok) - - assert Enum.empty?(response) - end - - test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do - other_user = insert(:user) - {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) - - response = - conn - |> assign(:user, nil) - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response(:ok) - - [%{"id" => id}] = response - assert id == other_user.id - end - - test "requires authentification for private posts", %{conn: conn, user: user} do - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - "status" => "@#{other_user.nickname} wanna get some #cofe together?", - "visibility" => "direct" - }) - - conn - |> assign(:user, nil) - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response(404) - - response = - build_conn() - |> assign(:user, other_user) - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response(200) - - assert [] == response - end - end - describe "POST /auth/password, with valid parameters" do setup %{conn: conn} do user = insert(:user) From 5ea5c58a85b7be56370b151ce8977982d47fde8c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 26 Sep 2019 14:28:35 +0700 Subject: [PATCH 238/272] Move view logic from StatusController.context to StatusView and add a test --- .../controllers/status_controller.ex | 27 +------------------ .../web/mastodon_api/views/status_view.ex | 14 ++++++++++ .../controllers/status_controller_test.exs | 21 +++++++++++++++ 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 89869bda0..f7da10289 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -21,7 +21,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.ScheduledActivityView - alias Pleroma.Web.MastodonAPI.StatusView @rate_limited_status_actions ~w(reblog unreblog favourite unfavourite create delete)a @@ -264,31 +263,7 @@ def context(%{assigns: %{user: user}} = conn, %{"id" => id}) do "exclude_id" => activity.id }) - # TODO: Move to view - grouped_activities = Enum.group_by(activities, fn %{id: id} -> id < activity.id end) - - result = %{ - ancestors: - StatusView.render( - "index.json", - for: user, - activities: grouped_activities[true] || [], - as: :activity - ) - |> Enum.reverse(), - # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart - descendants: - StatusView.render( - "index.json", - for: user, - activities: grouped_activities[false] || [], - as: :activity - ) - |> Enum.reverse() - # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart - } - - json(conn, result) + render(conn, "context.json", activity: activity, activities: activities, user: user) end end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 59bef30f2..715d40766 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -439,6 +439,20 @@ def render("poll.json", %{object: object} = opts) do end end + def render("context.json", %{activity: activity, activities: activities, user: user}) do + %{ancestors: ancestors, descendants: descendants} = + activities + |> Enum.reverse() + |> Enum.group_by(fn %{id: id} -> if id < activity.id, do: :ancestors, else: :descendants end) + |> Map.put_new(:ancestors, []) + |> Map.put_new(:descendants, []) + + %{ + ancestors: render("index.json", for: user, activities: ancestors, as: :activity), + descendants: render("index.json", for: user, activities: descendants, as: :activity) + } + end + def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do object = Object.normalize(activity) diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index f80ce7704..14c7bd6d9 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -1053,4 +1053,25 @@ test "requires authentification for private posts", %{conn: conn, user: user} do assert [] == response end end + + test "context" do + user = insert(:user) + + {:ok, %{id: id1}} = CommonAPI.post(user, %{"status" => "1"}) + {:ok, %{id: id2}} = CommonAPI.post(user, %{"status" => "2", "in_reply_to_status_id" => id1}) + {:ok, %{id: id3}} = CommonAPI.post(user, %{"status" => "3", "in_reply_to_status_id" => id2}) + {:ok, %{id: id4}} = CommonAPI.post(user, %{"status" => "4", "in_reply_to_status_id" => id3}) + {:ok, %{id: id5}} = CommonAPI.post(user, %{"status" => "5", "in_reply_to_status_id" => id4}) + + response = + build_conn() + |> assign(:user, nil) + |> get("/api/v1/statuses/#{id3}/context") + |> json_response(:ok) + + assert %{ + "ancestors" => [%{"id" => ^id1}, %{"id" => ^id2}], + "descendants" => [%{"id" => ^id4}, %{"id" => ^id5}] + } = response + end end From 14294243a294d764b449e1eae19c4cd87b9d4d82 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 27 Sep 2019 04:22:40 +0000 Subject: [PATCH 239/272] mastodon api: implement follow_requests_count --- .../web/mastodon_api/views/account_view.ex | 16 ++++ .../mastodon_api/views/account_view_test.exs | 75 +++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index a23aeea9b..8cf9e9d5c 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -166,6 +166,7 @@ defp do_render("account.json", %{user: user} = opts) do |> maybe_put_settings_store(user, opts[:for], opts) |> maybe_put_chat_token(user, opts[:for], opts) |> maybe_put_activation_status(user, opts[:for]) + |> maybe_put_follow_requests_count(user, opts[:for]) end defp username_from_nickname(string) when is_binary(string) do @@ -174,6 +175,21 @@ defp username_from_nickname(string) when is_binary(string) do defp username_from_nickname(_), do: nil + defp maybe_put_follow_requests_count( + data, + %User{id: user_id} = user, + %User{id: user_id} + ) do + count = + User.get_follow_requests(user) + |> length() + + data + |> Kernel.put_in([:follow_requests_count], count) + end + + defp maybe_put_follow_requests_count(data, _, _), do: data + defp maybe_put_settings( data, %User{id: user_id} = user, diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index f2f334992..d965f76bf 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -419,4 +419,79 @@ test "shows actual follower/following count to the account owner" do } = AccountView.render("account.json", %{user: user, for: user}) end end + + describe "follow requests counter" do + test "shows zero when no follow requests are pending" do + user = insert(:user) + + assert %{follow_requests_count: 0} = + AccountView.render("account.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{follow_requests_count: 0} = + AccountView.render("account.json", %{user: user, for: user}) + end + + test "shows non-zero when follow requests are pending" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{locked: true, follow_requests_count: 1} = + AccountView.render("account.json", %{user: user, for: user}) + end + + test "decreases when accepting a follow request" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{locked: true, follow_requests_count: 1} = + AccountView.render("account.json", %{user: user, for: user}) + + {:ok, _other_user} = CommonAPI.accept_follow_request(other_user, user) + + assert %{locked: true, follow_requests_count: 0} = + AccountView.render("account.json", %{user: user, for: user}) + end + + test "decreases when rejecting a follow request" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{locked: true, follow_requests_count: 1} = + AccountView.render("account.json", %{user: user, for: user}) + + {:ok, _other_user} = CommonAPI.reject_follow_request(other_user, user) + + assert %{locked: true, follow_requests_count: 0} = + AccountView.render("account.json", %{user: user, for: user}) + end + + test "shows non-zero when historical unapproved requests are present" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + {:ok, user} = User.update_info(user, &User.Info.user_upgrade(&1, %{locked: false})) + + assert %{locked: false, follow_requests_count: 1} = + AccountView.render("account.json", %{user: user, for: user}) + end + end end From 843c11d1f6f2455d5169952592b9b9d18be2a8fb Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 27 Sep 2019 04:24:20 +0000 Subject: [PATCH 240/272] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a8163135..2ea4dcc72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Pleroma API: `POST /api/v1/pleroma/subscription_notifications/clear` to clear all subscription notifications - Pleroma API: `POST /api/v1/pleroma/subscription_notifications/dismiss` to clear a subscription notification - Pleroma API: `DELETE /api/v1/pleroma/subscription_notifications/destroy_multiple` to clear multiple subscription notifications +- Mastodon API: Account entities now include `follow_requests_count` (planned Mastodon 3.x addition) ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) From 6c7c35dbe11c3871eea1a1c5745befdc2068e526 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 27 Sep 2019 11:55:47 +0700 Subject: [PATCH 241/272] Fix SubscriptionNotificationView --- .../web/pleroma_api/views/subscription_notification_view.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex index 0eccbcbb9..fc41a7389 100644 --- a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex +++ b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex @@ -36,19 +36,19 @@ def render("show.json", %{ "mention" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: activity, for: user}) + status: StatusView.render("show.json", %{activity: activity, for: user}) }) "favourite" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + status: StatusView.render("show.json", %{activity: parent_activity, for: user}) }) "reblog" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + status: StatusView.render("show.json", %{activity: parent_activity, for: user}) }) "follow" -> From 621377f378c7cfde88f87356e9fd65ed6d9f6d50 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 27 Sep 2019 13:06:25 +0700 Subject: [PATCH 242/272] Extract filter actions from `MastodonAPIController` to `FilterController` --- .../controllers/filter_controller.ex | 72 +++++++++ .../controllers/mastodon_api_controller.ex | 61 -------- .../views/subscription_notification_view.ex | 6 +- lib/pleroma/web/router.ex | 10 +- .../controllers/filter_controller_test.exs | 137 ++++++++++++++++++ .../mastodon_api_controller_test.exs | 129 ----------------- 6 files changed, 217 insertions(+), 198 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/filter_controller.ex create mode 100644 test/web/mastodon_api/controllers/filter_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex b/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex new file mode 100644 index 000000000..19041304e --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex @@ -0,0 +1,72 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FilterController do + use Pleroma.Web, :controller + + alias Pleroma.Filter + + @doc "GET /api/v1/filters" + def index(%{assigns: %{user: user}} = conn, _) do + filters = Filter.get_filters(user) + + render(conn, "filters.json", filters: filters) + end + + @doc "POST /api/v1/filters" + def create( + %{assigns: %{user: user}} = conn, + %{"phrase" => phrase, "context" => context} = params + ) do + query = %Filter{ + user_id: user.id, + phrase: phrase, + context: context, + hide: Map.get(params, "irreversible", false), + whole_word: Map.get(params, "boolean", true) + # expires_at + } + + {:ok, response} = Filter.create(query) + + render(conn, "filter.json", filter: response) + end + + @doc "GET /api/v1/filters/:id" + def show(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do + filter = Filter.get(filter_id, user) + + render(conn, "filter.json", filter: filter) + end + + @doc "PUT /api/v1/filters/:id" + def update( + %{assigns: %{user: user}} = conn, + %{"phrase" => phrase, "context" => context, "id" => filter_id} = params + ) do + query = %Filter{ + user_id: user.id, + filter_id: filter_id, + phrase: phrase, + context: context, + hide: Map.get(params, "irreversible", nil), + whole_word: Map.get(params, "boolean", true) + # expires_at + } + + {:ok, response} = Filter.update(query) + render(conn, "filter.json", filter: response) + end + + @doc "DELETE /api/v1/filters/:id" + def delete(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do + query = %Filter{ + user_id: user.id, + filter_id: filter_id + } + + {:ok, _} = Filter.delete(query) + json(conn, %{}) + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 82bba43e5..9e2382483 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -14,7 +14,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Config alias Pleroma.Conversation.Participation alias Pleroma.Emoji - alias Pleroma.Filter alias Pleroma.HTTP alias Pleroma.Object alias Pleroma.Pagination @@ -30,7 +29,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.AppView alias Pleroma.Web.MastodonAPI.ConversationView - alias Pleroma.Web.MastodonAPI.FilterView alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI alias Pleroma.Web.MastodonAPI.MastodonView @@ -1040,65 +1038,6 @@ def empty_object(conn, _) do json(conn, %{}) end - def get_filters(%{assigns: %{user: user}} = conn, _) do - filters = Filter.get_filters(user) - res = FilterView.render("filters.json", filters: filters) - json(conn, res) - end - - def create_filter( - %{assigns: %{user: user}} = conn, - %{"phrase" => phrase, "context" => context} = params - ) do - query = %Filter{ - user_id: user.id, - phrase: phrase, - context: context, - hide: Map.get(params, "irreversible", false), - whole_word: Map.get(params, "boolean", true) - # expires_at - } - - {:ok, response} = Filter.create(query) - res = FilterView.render("filter.json", filter: response) - json(conn, res) - end - - def get_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do - filter = Filter.get(filter_id, user) - res = FilterView.render("filter.json", filter: filter) - json(conn, res) - end - - def update_filter( - %{assigns: %{user: user}} = conn, - %{"phrase" => phrase, "context" => context, "id" => filter_id} = params - ) do - query = %Filter{ - user_id: user.id, - filter_id: filter_id, - phrase: phrase, - context: context, - hide: Map.get(params, "irreversible", nil), - whole_word: Map.get(params, "boolean", true) - # expires_at - } - - {:ok, response} = Filter.update(query) - res = FilterView.render("filter.json", filter: response) - json(conn, res) - end - - def delete_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do - query = %Filter{ - user_id: user.id, - filter_id: filter_id - } - - {:ok, _} = Filter.delete(query) - json(conn, %{}) - end - def suggestions(%{assigns: %{user: user}} = conn, _) do suggestions = Config.get(:suggestions) diff --git a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex index 0eccbcbb9..fc41a7389 100644 --- a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex +++ b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex @@ -36,19 +36,19 @@ def render("show.json", %{ "mention" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: activity, for: user}) + status: StatusView.render("show.json", %{activity: activity, for: user}) }) "favourite" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + status: StatusView.render("show.json", %{activity: parent_activity, for: user}) }) "reblog" -> response |> Map.merge(%{ - status: StatusView.render("status.json", %{activity: parent_activity, for: user}) + status: StatusView.render("show.json", %{activity: parent_activity, for: user}) }) "follow" -> diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8bf55631e..30ebf435c 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -348,7 +348,7 @@ defmodule Pleroma.Web.Router do get("/domain_blocks", MastodonAPIController, :domain_blocks) - get("/filters", MastodonAPIController, :get_filters) + get("/filters", FilterController, :index) get("/suggestions", MastodonAPIController, :suggestions) @@ -392,10 +392,10 @@ defmodule Pleroma.Web.Router do post("/lists/:id/accounts", ListController, :add_to_list) delete("/lists/:id/accounts", ListController, :remove_from_list) - post("/filters", MastodonAPIController, :create_filter) - get("/filters/:id", MastodonAPIController, :get_filter) - put("/filters/:id", MastodonAPIController, :update_filter) - delete("/filters/:id", MastodonAPIController, :delete_filter) + post("/filters", FilterController, :create) + get("/filters/:id", FilterController, :show) + put("/filters/:id", FilterController, :update) + delete("/filters/:id", FilterController, :delete) patch("/pleroma/accounts/update_avatar", MastodonAPIController, :update_avatar) patch("/pleroma/accounts/update_banner", MastodonAPIController, :update_banner) diff --git a/test/web/mastodon_api/controllers/filter_controller_test.exs b/test/web/mastodon_api/controllers/filter_controller_test.exs new file mode 100644 index 000000000..5d5b56c8e --- /dev/null +++ b/test/web/mastodon_api/controllers/filter_controller_test.exs @@ -0,0 +1,137 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.Web.MastodonAPI.FilterView + + import Pleroma.Factory + + test "creating a filter", %{conn: conn} do + user = insert(:user) + + filter = %Pleroma.Filter{ + phrase: "knights", + context: ["home"] + } + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context}) + + assert response = json_response(conn, 200) + assert response["phrase"] == filter.phrase + assert response["context"] == filter.context + assert response["irreversible"] == false + assert response["id"] != nil + assert response["id"] != "" + end + + test "fetching a list of filters", %{conn: conn} do + user = insert(:user) + + query_one = %Pleroma.Filter{ + user_id: user.id, + filter_id: 1, + phrase: "knights", + context: ["home"] + } + + query_two = %Pleroma.Filter{ + user_id: user.id, + filter_id: 2, + phrase: "who", + context: ["home"] + } + + {:ok, filter_one} = Pleroma.Filter.create(query_one) + {:ok, filter_two} = Pleroma.Filter.create(query_two) + + response = + conn + |> assign(:user, user) + |> get("/api/v1/filters") + |> json_response(200) + + assert response == + render_json( + FilterView, + "filters.json", + filters: [filter_two, filter_one] + ) + end + + test "get a filter", %{conn: conn} do + user = insert(:user) + + query = %Pleroma.Filter{ + user_id: user.id, + filter_id: 2, + phrase: "knight", + context: ["home"] + } + + {:ok, filter} = Pleroma.Filter.create(query) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/filters/#{filter.filter_id}") + + assert _response = json_response(conn, 200) + end + + test "update a filter", %{conn: conn} do + user = insert(:user) + + query = %Pleroma.Filter{ + user_id: user.id, + filter_id: 2, + phrase: "knight", + context: ["home"] + } + + {:ok, _filter} = Pleroma.Filter.create(query) + + new = %Pleroma.Filter{ + phrase: "nii", + context: ["home"] + } + + conn = + conn + |> assign(:user, user) + |> put("/api/v1/filters/#{query.filter_id}", %{ + phrase: new.phrase, + context: new.context + }) + + assert response = json_response(conn, 200) + assert response["phrase"] == new.phrase + assert response["context"] == new.context + end + + test "delete a filter", %{conn: conn} do + user = insert(:user) + + query = %Pleroma.Filter{ + user_id: user.id, + filter_id: 2, + phrase: "knight", + context: ["home"] + } + + {:ok, filter} = Pleroma.Filter.create(query) + + conn = + conn + |> assign(:user, user) + |> delete("/api/v1/filters/#{filter.filter_id}") + + assert response = json_response(conn, 200) + assert response == %{} + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 6435ad7a9..9c6cdbd7a 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -16,7 +16,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.FilterView alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Token alias Pleroma.Web.Push @@ -268,134 +267,6 @@ test "creates an oauth app", %{conn: conn} do assert expected == json_response(conn, 200) end - describe "filters" do - test "creating a filter", %{conn: conn} do - user = insert(:user) - - filter = %Pleroma.Filter{ - phrase: "knights", - context: ["home"] - } - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context}) - - assert response = json_response(conn, 200) - assert response["phrase"] == filter.phrase - assert response["context"] == filter.context - assert response["irreversible"] == false - assert response["id"] != nil - assert response["id"] != "" - end - - test "fetching a list of filters", %{conn: conn} do - user = insert(:user) - - query_one = %Pleroma.Filter{ - user_id: user.id, - filter_id: 1, - phrase: "knights", - context: ["home"] - } - - query_two = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "who", - context: ["home"] - } - - {:ok, filter_one} = Pleroma.Filter.create(query_one) - {:ok, filter_two} = Pleroma.Filter.create(query_two) - - response = - conn - |> assign(:user, user) - |> get("/api/v1/filters") - |> json_response(200) - - assert response == - render_json( - FilterView, - "filters.json", - filters: [filter_two, filter_one] - ) - end - - test "get a filter", %{conn: conn} do - user = insert(:user) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"] - } - - {:ok, filter} = Pleroma.Filter.create(query) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/filters/#{filter.filter_id}") - - assert _response = json_response(conn, 200) - end - - test "update a filter", %{conn: conn} do - user = insert(:user) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"] - } - - {:ok, _filter} = Pleroma.Filter.create(query) - - new = %Pleroma.Filter{ - phrase: "nii", - context: ["home"] - } - - conn = - conn - |> assign(:user, user) - |> put("/api/v1/filters/#{query.filter_id}", %{ - phrase: new.phrase, - context: new.context - }) - - assert response = json_response(conn, 200) - assert response["phrase"] == new.phrase - assert response["context"] == new.context - end - - test "delete a filter", %{conn: conn} do - user = insert(:user) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"] - } - - {:ok, filter} = Pleroma.Filter.create(query) - - conn = - conn - |> assign(:user, user) - |> delete("/api/v1/filters/#{filter.filter_id}") - - assert response = json_response(conn, 200) - assert response == %{} - end - end - describe "user timelines" do test "gets a users statuses", %{conn: conn} do user_one = insert(:user) From 0a5b106ddd333f2dec2b62badeca98e6091ba805 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 27 Sep 2019 13:35:45 +0700 Subject: [PATCH 243/272] Extract scheduled statuses actions from `MastodonAPIController` to `ScheduledActivityController` --- .../controllers/mastodon_api_controller.ex | 51 ----- .../scheduled_activity_controller.ex | 51 +++++ lib/pleroma/web/router.ex | 8 +- .../scheduled_activity_controller_test.exs | 113 ++++++++++ .../controllers/status_controller_test.exs | 112 +++++++++ .../mastodon_api_controller_test.exs | 212 ------------------ 6 files changed, 280 insertions(+), 267 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex create mode 100644 test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 82bba43e5..1f6211917 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -20,7 +20,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Pagination alias Pleroma.Plugs.RateLimiter alias Pleroma.Repo - alias Pleroma.ScheduledActivity alias Pleroma.Stats alias Pleroma.User alias Pleroma.Web @@ -35,7 +34,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.MastodonAPI alias Pleroma.Web.MastodonAPI.MastodonView alias Pleroma.Web.MastodonAPI.ReportView - alias Pleroma.Web.MastodonAPI.ScheduledActivityView alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy alias Pleroma.Web.OAuth.App @@ -396,55 +394,6 @@ def poll_vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choic end end - def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do - with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do - conn - |> add_link_headers(scheduled_activities) - |> put_view(ScheduledActivityView) - |> render("index.json", %{scheduled_activities: scheduled_activities}) - end - end - - def show_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do - with %ScheduledActivity{} = scheduled_activity <- - ScheduledActivity.get(user, scheduled_activity_id) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) - else - _ -> {:error, :not_found} - end - end - - def update_scheduled_status( - %{assigns: %{user: user}} = conn, - %{"id" => scheduled_activity_id} = params - ) do - with %ScheduledActivity{} = scheduled_activity <- - ScheduledActivity.get(user, scheduled_activity_id), - {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) - else - nil -> {:error, :not_found} - error -> error - end - end - - def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do - with %ScheduledActivity{} = scheduled_activity <- - ScheduledActivity.get(user, scheduled_activity_id), - {:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) - else - nil -> {:error, :not_found} - error -> error - end - end - def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do id = List.wrap(id) q = from(u in User, where: u.id in ^id) diff --git a/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex b/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex new file mode 100644 index 000000000..0a56b10b6 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + + alias Pleroma.ScheduledActivity + alias Pleroma.Web.MastodonAPI.MastodonAPI + + plug(:assign_scheduled_activity when action != :index) + + action_fallback(Pleroma.Web.MastodonAPI.FallbackController) + + @doc "GET /api/v1/scheduled_statuses" + def index(%{assigns: %{user: user}} = conn, params) do + with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do + conn + |> add_link_headers(scheduled_activities) + |> render("index.json", scheduled_activities: scheduled_activities) + end + end + + @doc "GET /api/v1/scheduled_statuses/:id" + def show(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, _params) do + render(conn, "show.json", scheduled_activity: scheduled_activity) + end + + @doc "PUT /api/v1/scheduled_statuses/:id" + def update(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, params) do + with {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do + render(conn, "show.json", scheduled_activity: scheduled_activity) + end + end + + @doc "DELETE /api/v1/scheduled_statuses/:id" + def delete(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, _params) do + with {:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do + render(conn, "show.json", scheduled_activity: scheduled_activity) + end + end + + defp assign_scheduled_activity(%{assigns: %{user: user}, params: %{"id" => id}} = conn, _) do + case ScheduledActivity.get(user, id) do + %ScheduledActivity{} = activity -> assign(conn, :scheduled_activity, activity) + nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt() + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8bf55631e..e12e6d313 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -339,8 +339,8 @@ defmodule Pleroma.Web.Router do post("/notifications/dismiss", NotificationController, :dismiss) delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple) - get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses) - get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status) + get("/scheduled_statuses", ScheduledActivityController, :index) + get("/scheduled_statuses/:id", ScheduledActivityController, :show) get("/lists", ListController, :index) get("/lists/:id", ListController, :show) @@ -377,8 +377,8 @@ defmodule Pleroma.Web.Router do post("/statuses/:id/mute", StatusController, :mute_conversation) post("/statuses/:id/unmute", StatusController, :unmute_conversation) - put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status) - delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status) + put("/scheduled_statuses/:id", ScheduledActivityController, :update) + delete("/scheduled_statuses/:id", ScheduledActivityController, :delete) post("/polls/:id/votes", MastodonAPIController, :poll_vote) diff --git a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs b/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs new file mode 100644 index 000000000..9ad6a4fa7 --- /dev/null +++ b/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs @@ -0,0 +1,113 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.Repo + alias Pleroma.ScheduledActivity + + import Pleroma.Factory + + test "shows scheduled activities", %{conn: conn} do + user = insert(:user) + scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string() + scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string() + scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string() + scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string() + + conn = + conn + |> assign(:user, user) + + # min_id + conn_res = + conn + |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}") + + result = json_response(conn_res, 200) + assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result + + # since_id + conn_res = + conn + |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}") + + result = json_response(conn_res, 200) + assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result + + # max_id + conn_res = + conn + |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}") + + result = json_response(conn_res, 200) + assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result + end + + test "shows a scheduled activity", %{conn: conn} do + user = insert(:user) + scheduled_activity = insert(:scheduled_activity, user: user) + + res_conn = + conn + |> assign(:user, user) + |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + + assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200) + assert scheduled_activity_id == scheduled_activity.id |> to_string() + + res_conn = + conn + |> assign(:user, user) + |> get("/api/v1/scheduled_statuses/404") + + assert %{"error" => "Record not found"} = json_response(res_conn, 404) + end + + test "updates a scheduled activity", %{conn: conn} do + user = insert(:user) + scheduled_activity = insert(:scheduled_activity, user: user) + + new_scheduled_at = + NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + + res_conn = + conn + |> assign(:user, user) + |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{ + scheduled_at: new_scheduled_at + }) + + assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200) + assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at) + + res_conn = + conn + |> assign(:user, user) + |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at}) + + assert %{"error" => "Record not found"} = json_response(res_conn, 404) + end + + test "deletes a scheduled activity", %{conn: conn} do + user = insert(:user) + scheduled_activity = insert(:scheduled_activity, user: user) + + res_conn = + conn + |> assign(:user, user) + |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + + assert %{} = json_response(res_conn, 200) + assert nil == Repo.get(ScheduledActivity, scheduled_activity.id) + + res_conn = + conn + |> assign(:user, user) + |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + + assert %{"error" => "Record not found"} = json_response(res_conn, 404) + end +end diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index 14c7bd6d9..cbd4bafe8 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -9,7 +9,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do alias Pleroma.ActivityExpiration alias Pleroma.Config alias Pleroma.Object + alias Pleroma.Repo + alias Pleroma.ScheduledActivity alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -224,6 +227,115 @@ test "posting a direct status", %{conn: conn} do end end + describe "posting scheduled statuses" do + test "creates a scheduled activity", %{conn: conn} do + user = insert(:user) + scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "status" => "scheduled", + "scheduled_at" => scheduled_at + }) + + assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200) + assert expected_scheduled_at == CommonAPI.Utils.to_masto_date(scheduled_at) + assert [] == Repo.all(Activity) + end + + test "creates a scheduled activity with a media attachment", %{conn: conn} do + user = insert(:user) + scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "media_ids" => [to_string(upload.id)], + "status" => "scheduled", + "scheduled_at" => scheduled_at + }) + + assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200) + assert %{"type" => "image"} = media_attachment + end + + test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now", + %{conn: conn} do + user = insert(:user) + + scheduled_at = + NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "status" => "not scheduled", + "scheduled_at" => scheduled_at + }) + + assert %{"content" => "not scheduled"} = json_response(conn, 200) + assert [] == Repo.all(ScheduledActivity) + end + + test "returns error when daily user limit is exceeded", %{conn: conn} do + user = insert(:user) + + today = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(:timer.minutes(6), :millisecond) + |> NaiveDateTime.to_iso8601() + + attrs = %{params: %{}, scheduled_at: today} + {:ok, _} = ScheduledActivity.create(user, attrs) + {:ok, _} = ScheduledActivity.create(user, attrs) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today}) + + assert %{"error" => "daily limit exceeded"} == json_response(conn, 422) + end + + test "returns error when total user limit is exceeded", %{conn: conn} do + user = insert(:user) + + today = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(:timer.minutes(6), :millisecond) + |> NaiveDateTime.to_iso8601() + + tomorrow = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(:timer.hours(36), :millisecond) + |> NaiveDateTime.to_iso8601() + + attrs = %{params: %{}, scheduled_at: today} + {:ok, _} = ScheduledActivity.create(user, attrs) + {:ok, _} = ScheduledActivity.create(user, attrs) + {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow}) + + assert %{"error" => "total limit exceeded"} == json_response(conn, 422) + end + end + describe "posting polls" do test "posting a poll", %{conn: conn} do user = insert(:user) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 6435ad7a9..e77610ba3 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -6,12 +6,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do use Pleroma.Web.ConnCase alias Ecto.Changeset - alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo - alias Pleroma.ScheduledActivity alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -1810,216 +1808,6 @@ test "redirects to the getting-started page when referer is not present", %{conn end end - describe "scheduled activities" do - test "creates a scheduled activity", %{conn: conn} do - user = insert(:user) - scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "status" => "scheduled", - "scheduled_at" => scheduled_at - }) - - assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200) - assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at) - assert [] == Repo.all(Activity) - end - - test "creates a scheduled activity with a media attachment", %{conn: conn} do - user = insert(:user) - scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "media_ids" => [to_string(upload.id)], - "status" => "scheduled", - "scheduled_at" => scheduled_at - }) - - assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200) - assert %{"type" => "image"} = media_attachment - end - - test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now", - %{conn: conn} do - user = insert(:user) - - scheduled_at = - NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{ - "status" => "not scheduled", - "scheduled_at" => scheduled_at - }) - - assert %{"content" => "not scheduled"} = json_response(conn, 200) - assert [] == Repo.all(ScheduledActivity) - end - - test "returns error when daily user limit is exceeded", %{conn: conn} do - user = insert(:user) - - today = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(6), :millisecond) - |> NaiveDateTime.to_iso8601() - - attrs = %{params: %{}, scheduled_at: today} - {:ok, _} = ScheduledActivity.create(user, attrs) - {:ok, _} = ScheduledActivity.create(user, attrs) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today}) - - assert %{"error" => "daily limit exceeded"} == json_response(conn, 422) - end - - test "returns error when total user limit is exceeded", %{conn: conn} do - user = insert(:user) - - today = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(6), :millisecond) - |> NaiveDateTime.to_iso8601() - - tomorrow = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.hours(36), :millisecond) - |> NaiveDateTime.to_iso8601() - - attrs = %{params: %{}, scheduled_at: today} - {:ok, _} = ScheduledActivity.create(user, attrs) - {:ok, _} = ScheduledActivity.create(user, attrs) - {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow}) - - assert %{"error" => "total limit exceeded"} == json_response(conn, 422) - end - - test "shows scheduled activities", %{conn: conn} do - user = insert(:user) - scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string() - scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string() - scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string() - scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string() - - conn = - conn - |> assign(:user, user) - - # min_id - conn_res = - conn - |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result - - # since_id - conn_res = - conn - |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result - - # max_id - conn_res = - conn - |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}") - - result = json_response(conn_res, 200) - assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result - end - - test "shows a scheduled activity", %{conn: conn} do - user = insert(:user) - scheduled_activity = insert(:scheduled_activity, user: user) - - res_conn = - conn - |> assign(:user, user) - |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - - assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200) - assert scheduled_activity_id == scheduled_activity.id |> to_string() - - res_conn = - conn - |> assign(:user, user) - |> get("/api/v1/scheduled_statuses/404") - - assert %{"error" => "Record not found"} = json_response(res_conn, 404) - end - - test "updates a scheduled activity", %{conn: conn} do - user = insert(:user) - scheduled_activity = insert(:scheduled_activity, user: user) - - new_scheduled_at = - NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) - - res_conn = - conn - |> assign(:user, user) - |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{ - scheduled_at: new_scheduled_at - }) - - assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200) - assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at) - - res_conn = - conn - |> assign(:user, user) - |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at}) - - assert %{"error" => "Record not found"} = json_response(res_conn, 404) - end - - test "deletes a scheduled activity", %{conn: conn} do - user = insert(:user) - scheduled_activity = insert(:scheduled_activity, user: user) - - res_conn = - conn - |> assign(:user, user) - |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - - assert %{} = json_response(res_conn, 200) - assert nil == Repo.get(ScheduledActivity, scheduled_activity.id) - - res_conn = - conn - |> assign(:user, user) - |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - - assert %{"error" => "Record not found"} = json_response(res_conn, 404) - end - end - describe "create account by app" do test "Account registration via Application", %{conn: conn} do conn = From 8d315301193a39575291db5c5d9fabe492261664 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 27 Sep 2019 11:46:20 +0700 Subject: [PATCH 244/272] Cleanup ScheduledActivityView --- .../views/scheduled_activity_view.ex | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex index 0aae15ab9..fc042a276 100644 --- a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex +++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex @@ -7,11 +7,10 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do alias Pleroma.ScheduledActivity alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.ScheduledActivityView alias Pleroma.Web.MastodonAPI.StatusView def render("index.json", %{scheduled_activities: scheduled_activities}) do - render_many(scheduled_activities, ScheduledActivityView, "show.json") + render_many(scheduled_activities, __MODULE__, "show.json") end def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_activity}) do @@ -24,12 +23,8 @@ def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_a end defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do - try do - attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment) - Map.put(data, :media_attachments, attachments) - rescue - _ -> data - end + attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment) + Map.put(data, :media_attachments, attachments) end defp with_media_attachments(data, _), do: data @@ -45,13 +40,9 @@ defp status_params(params) do in_reply_to_id: params["in_reply_to_id"] } - data = - if media_ids = params["media_ids"] do - Map.put(data, :media_ids, media_ids) - else - data - end - - data + case params["media_ids"] do + nil -> data + media_ids -> Map.put(data, :media_ids, media_ids) + end end end From 99c5a35890f470c30661e900380bcd7c4b75d6d0 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 27 Sep 2019 14:25:17 +0700 Subject: [PATCH 245/272] Extract follow requests actions from `MastodonAPIController` to `FollowRequestController` --- .../controllers/follow_request_controller.ex | 49 +++++++++++ .../controllers/mastodon_api_controller.ex | 36 --------- lib/pleroma/web/router.ex | 6 +- .../follow_request_controller_test.exs | 81 +++++++++++++++++++ .../mastodon_api_controller_test.exs | 67 --------------- 5 files changed, 133 insertions(+), 106 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex create mode 100644 test/web/mastodon_api/controllers/follow_request_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex new file mode 100644 index 000000000..267014b97 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FollowRequestController do + use Pleroma.Web, :controller + + alias Pleroma.User + alias Pleroma.Web.CommonAPI + + plug(:put_view, Pleroma.Web.MastodonAPI.AccountView) + plug(:assign_follower when action != :index) + + action_fallback(:errors) + + @doc "GET /api/v1/follow_requests" + def index(%{assigns: %{user: followed}} = conn, _params) do + follow_requests = User.get_follow_requests(followed) + + render(conn, "accounts.json", for: followed, users: follow_requests, as: :user) + end + + @doc "POST /api/v1/follow_requests/:id/authorize" + def authorize(%{assigns: %{user: followed, follower: follower}} = conn, _params) do + with {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do + render(conn, "relationship.json", user: followed, target: follower) + end + end + + @doc "POST /api/v1/follow_requests/:id/reject" + def reject(%{assigns: %{user: followed, follower: follower}} = conn, _params) do + with {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do + render(conn, "relationship.json", user: followed, target: follower) + end + end + + defp assign_follower(%{params: %{"id" => id}} = conn, _) do + case User.get_cached_by_id(id) do + %User{} = follower -> assign(conn, :follower, follower) + nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt() + end + end + + defp errors(conn, {:error, message}) do + conn + |> put_status(:forbidden) + |> json(%{error: message}) + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 82bba43e5..0ee9f034a 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -550,42 +550,6 @@ def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do end end - def follow_requests(%{assigns: %{user: followed}} = conn, _params) do - follow_requests = User.get_follow_requests(followed) - - conn - |> put_view(AccountView) - |> render("accounts.json", %{for: followed, users: follow_requests, as: :user}) - end - - def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do - with %User{} = follower <- User.get_cached_by_id(id), - {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do - conn - |> put_view(AccountView) - |> render("relationship.json", %{user: followed, target: follower}) - else - {:error, message} -> - conn - |> put_status(:forbidden) - |> json(%{error: message}) - end - end - - def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do - with %User{} = follower <- User.get_cached_by_id(id), - {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do - conn - |> put_view(AccountView) - |> render("relationship.json", %{user: followed, target: follower}) - else - {:error, message} -> - conn - |> put_status(:forbidden) - |> json(%{error: message}) - end - end - def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)}, {_, true} <- {:followed, follower.id != followed.id}, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8bf55631e..72d3827a5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -323,7 +323,7 @@ defmodule Pleroma.Web.Router do get("/accounts/:id/lists", MastodonAPIController, :account_lists) get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array) - get("/follow_requests", MastodonAPIController, :follow_requests) + get("/follow_requests", FollowRequestController, :index) get("/blocks", MastodonAPIController, :blocks) get("/mutes", MastodonAPIController, :mutes) @@ -419,8 +419,8 @@ defmodule Pleroma.Web.Router do post("/accounts/:id/mute", MastodonAPIController, :mute) post("/accounts/:id/unmute", MastodonAPIController, :unmute) - post("/follow_requests/:id/authorize", MastodonAPIController, :authorize_follow_request) - post("/follow_requests/:id/reject", MastodonAPIController, :reject_follow_request) + post("/follow_requests/:id/authorize", FollowRequestController, :authorize) + post("/follow_requests/:id/reject", FollowRequestController, :reject) post("/domain_blocks", MastodonAPIController, :block_domain) delete("/domain_blocks", MastodonAPIController, :unblock_domain) diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/web/mastodon_api/controllers/follow_request_controller_test.exs new file mode 100644 index 000000000..4bf292df5 --- /dev/null +++ b/test/web/mastodon_api/controllers/follow_request_controller_test.exs @@ -0,0 +1,81 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + + import Pleroma.Factory + + describe "locked accounts" do + test "/api/v1/follow_requests works" do + user = insert(:user, %{info: %User.Info{locked: true}}) + other_user = insert(:user) + + {:ok, _activity} = ActivityPub.follow(other_user, user) + + user = User.get_cached_by_id(user.id) + other_user = User.get_cached_by_id(other_user.id) + + assert User.following?(other_user, user) == false + + conn = + build_conn() + |> assign(:user, user) + |> get("/api/v1/follow_requests") + + assert [relationship] = json_response(conn, 200) + assert to_string(other_user.id) == relationship["id"] + end + + test "/api/v1/follow_requests/:id/authorize works" do + user = insert(:user, %{info: %User.Info{locked: true}}) + other_user = insert(:user) + + {:ok, _activity} = ActivityPub.follow(other_user, user) + + user = User.get_cached_by_id(user.id) + other_user = User.get_cached_by_id(other_user.id) + + assert User.following?(other_user, user) == false + + conn = + build_conn() + |> assign(:user, user) + |> post("/api/v1/follow_requests/#{other_user.id}/authorize") + + assert relationship = json_response(conn, 200) + assert to_string(other_user.id) == relationship["id"] + + user = User.get_cached_by_id(user.id) + other_user = User.get_cached_by_id(other_user.id) + + assert User.following?(other_user, user) == true + end + + test "/api/v1/follow_requests/:id/reject works" do + user = insert(:user, %{info: %User.Info{locked: true}}) + other_user = insert(:user) + + {:ok, _activity} = ActivityPub.follow(other_user, user) + + user = User.get_cached_by_id(user.id) + + conn = + build_conn() + |> assign(:user, user) + |> post("/api/v1/follow_requests/#{other_user.id}/reject") + + assert relationship = json_response(conn, 200) + assert to_string(other_user.id) == relationship["id"] + + user = User.get_cached_by_id(user.id) + other_user = User.get_cached_by_id(other_user.id) + + assert User.following?(other_user, user) == false + end + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 6435ad7a9..60ade00d2 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -570,51 +570,6 @@ test "returns uploaded image", %{conn: conn, image: image} do end describe "locked accounts" do - test "/api/v1/follow_requests works" do - user = insert(:user, %{info: %User.Info{locked: true}}) - other_user = insert(:user) - - {:ok, _activity} = ActivityPub.follow(other_user, user) - - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - assert User.following?(other_user, user) == false - - conn = - build_conn() - |> assign(:user, user) - |> get("/api/v1/follow_requests") - - assert [relationship] = json_response(conn, 200) - assert to_string(other_user.id) == relationship["id"] - end - - test "/api/v1/follow_requests/:id/authorize works" do - user = insert(:user, %{info: %User.Info{locked: true}}) - other_user = insert(:user) - - {:ok, _activity} = ActivityPub.follow(other_user, user) - - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - assert User.following?(other_user, user) == false - - conn = - build_conn() - |> assign(:user, user) - |> post("/api/v1/follow_requests/#{other_user.id}/authorize") - - assert relationship = json_response(conn, 200) - assert to_string(other_user.id) == relationship["id"] - - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - assert User.following?(other_user, user) == true - end - test "verify_credentials", %{conn: conn} do user = insert(:user, %{info: %User.Info{default_scope: "private"}}) @@ -626,28 +581,6 @@ test "verify_credentials", %{conn: conn} do assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200) assert id == to_string(user.id) end - - test "/api/v1/follow_requests/:id/reject works" do - user = insert(:user, %{info: %User.Info{locked: true}}) - other_user = insert(:user) - - {:ok, _activity} = ActivityPub.follow(other_user, user) - - user = User.get_cached_by_id(user.id) - - conn = - build_conn() - |> assign(:user, user) - |> post("/api/v1/follow_requests/#{other_user.id}/reject") - - assert relationship = json_response(conn, 200) - assert to_string(other_user.id) == relationship["id"] - - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - assert User.following?(other_user, user) == false - end end describe "account fetching" do From 408750b94e1374c815c80a1060892231f40b54fb Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 27 Sep 2019 14:28:05 +0700 Subject: [PATCH 246/272] Extract domain blocks actions from `MastodonAPIController` to `DomainBlockController` --- .../controllers/domain_block_controller.ex | 26 ++++++++++ .../controllers/mastodon_api_controller.ex | 14 ----- lib/pleroma/web/router.ex | 6 +-- .../domain_block_controller_test.exs | 51 +++++++++++++++++++ .../mastodon_api_controller_test.exs | 40 --------------- 5 files changed, 80 insertions(+), 57 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex create mode 100644 test/web/mastodon_api/controllers/domain_block_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex new file mode 100644 index 000000000..03db6c9b8 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex @@ -0,0 +1,26 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.DomainBlockController do + use Pleroma.Web, :controller + + alias Pleroma.User + + @doc "GET /api/v1/domain_blocks" + def index(%{assigns: %{user: %{info: info}}} = conn, _) do + json(conn, Map.get(info, :domain_blocks, [])) + end + + @doc "POST /api/v1/domain_blocks" + def create(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do + User.block_domain(blocker, domain) + json(conn, %{}) + end + + @doc "DELETE /api/v1/domain_blocks" + def delete(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do + User.unblock_domain(blocker, domain) + json(conn, %{}) + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 82bba43e5..e96bf6fd9 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -715,20 +715,6 @@ def blocks(%{assigns: %{user: user}} = conn, _) do end end - def domain_blocks(%{assigns: %{user: %{info: info}}} = conn, _) do - json(conn, info.domain_blocks || []) - end - - def block_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do - User.block_domain(blocker, domain) - json(conn, %{}) - end - - def unblock_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do - User.unblock_domain(blocker, domain) - json(conn, %{}) - end - def subscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %User{} = subscription_target <- User.get_cached_by_id(id), {:ok, subscription_target} = User.subscribe(user, subscription_target) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8bf55631e..d370f30db 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -346,7 +346,7 @@ defmodule Pleroma.Web.Router do get("/lists/:id", ListController, :show) get("/lists/:id/accounts", ListController, :list_accounts) - get("/domain_blocks", MastodonAPIController, :domain_blocks) + get("/domain_blocks", DomainBlockController, :index) get("/filters", MastodonAPIController, :get_filters) @@ -422,8 +422,8 @@ defmodule Pleroma.Web.Router do post("/follow_requests/:id/authorize", MastodonAPIController, :authorize_follow_request) post("/follow_requests/:id/reject", MastodonAPIController, :reject_follow_request) - post("/domain_blocks", MastodonAPIController, :block_domain) - delete("/domain_blocks", MastodonAPIController, :unblock_domain) + post("/domain_blocks", DomainBlockController, :create) + delete("/domain_blocks", DomainBlockController, :delete) post("/pleroma/accounts/:id/subscribe", MastodonAPIController, :subscribe) post("/pleroma/accounts/:id/unsubscribe", MastodonAPIController, :unsubscribe) diff --git a/test/web/mastodon_api/controllers/domain_block_controller_test.exs b/test/web/mastodon_api/controllers/domain_block_controller_test.exs new file mode 100644 index 000000000..3c3558385 --- /dev/null +++ b/test/web/mastodon_api/controllers/domain_block_controller_test.exs @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.User + + import Pleroma.Factory + + test "blocking / unblocking a domain", %{conn: conn} do + user = insert(:user) + other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"}) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) + + assert %{} = json_response(conn, 200) + user = User.get_cached_by_ap_id(user.ap_id) + assert User.blocks?(user, other_user) + + conn = + build_conn() + |> assign(:user, user) + |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) + + assert %{} = json_response(conn, 200) + user = User.get_cached_by_ap_id(user.ap_id) + refute User.blocks?(user, other_user) + end + + test "getting a list of domain blocks", %{conn: conn} do + user = insert(:user) + + {:ok, user} = User.block_domain(user, "bad.site") + {:ok, user} = User.block_domain(user, "even.worse.site") + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/domain_blocks") + + domain_blocks = json_response(conn, 200) + + assert "bad.site" in domain_blocks + assert "even.worse.site" in domain_blocks + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 6435ad7a9..5bd76d431 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1176,46 +1176,6 @@ test "getting a list of blocks", %{conn: conn} do assert [%{"id" => ^other_user_id}] = json_response(conn, 200) end - test "blocking / unblocking a domain", %{conn: conn} do - user = insert(:user) - other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"}) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) - - assert %{} = json_response(conn, 200) - user = User.get_cached_by_ap_id(user.ap_id) - assert User.blocks?(user, other_user) - - conn = - build_conn() - |> assign(:user, user) - |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) - - assert %{} = json_response(conn, 200) - user = User.get_cached_by_ap_id(user.ap_id) - refute User.blocks?(user, other_user) - end - - test "getting a list of domain blocks", %{conn: conn} do - user = insert(:user) - - {:ok, user} = User.block_domain(user, "bad.site") - {:ok, user} = User.block_domain(user, "even.worse.site") - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/domain_blocks") - - domain_blocks = json_response(conn, 200) - - assert "bad.site" in domain_blocks - assert "even.worse.site" in domain_blocks - end - test "unimplemented follow_requests, blocks, domain blocks" do user = insert(:user) From f9380289eb251c818e87e8f0ad0a41fc8bdd90aa Mon Sep 17 00:00:00 2001 From: minibikini Date: Fri, 27 Sep 2019 21:59:23 +0000 Subject: [PATCH 247/272] Add `remote_ip` plug --- CHANGELOG.md | 1 + config/config.exs | 2 + config/description.exs | 36 +++++++++++++++++ docs/config.md | 15 +++++++ installation/pleroma.nginx | 1 + lib/pleroma/plugs/remote_ip.ex | 54 +++++++++++++++++++++++++ lib/pleroma/web/endpoint.ex | 5 +-- mix.exs | 3 ++ mix.lock | 2 + test/plugs/remote_ip_test.exs | 72 ++++++++++++++++++++++++++++++++++ 10 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 lib/pleroma/plugs/remote_ip.ex create mode 100644 test/plugs/remote_ip_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a8163135..1d307f0e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -113,6 +113,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=` for resending account confirmation. - Pleroma API: Email change endpoint. - Admin API: Added moderation log +- Support for `X-Forwarded-For` and similar HTTP headers which used by reverse proxies to pass a real user IP address to the backend. Must not be enabled unless your instance is behind at least one reverse proxy (such as Nginx, Apache HTTPD or Varnish Cache). - Web response cache (currently, enabled for ActivityPub) - Mastodon API: Added an endpoint to get multiple statuses by IDs (`GET /api/v1/statuses/?ids[]=1&ids[]=2`) - ActivityPub: Add ActivityPub actor's `discoverable` parameter. diff --git a/config/config.exs b/config/config.exs index 403ade60d..36bea19a0 100644 --- a/config/config.exs +++ b/config/config.exs @@ -591,6 +591,8 @@ config :pleroma, Pleroma.ActivityExpiration, enabled: true +config :pleroma, Pleroma.Plugs.RemoteIp, enabled: false + config :pleroma, :web_cache_ttl, activity_pub: nil, activity_pub_question: 30_000 diff --git a/config/description.exs b/config/description.exs index 38b30bbf6..4547ea368 100644 --- a/config/description.exs +++ b/config/description.exs @@ -2687,6 +2687,42 @@ } ] }, + %{ + group: :pleroma, + key: Pleroma.Plugs.RemoteIp, + type: :group, + description: """ + **If your instance is not behind at least one reverse proxy, you should not enable this plug.** + + `Pleroma.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration. + """, + children: [ + %{ + key: :enabled, + type: :boolean, + description: "Enable/disable the plug. Defaults to `false`.", + suggestions: [true, false] + }, + %{ + key: :headers, + type: {:list, :string}, + description: + "A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Defaults to `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`." + }, + %{ + key: :proxies, + type: {:list, :string}, + description: + "A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Defaults to `[]`." + }, + %{ + key: :reserved, + type: {:list, :string}, + description: + "Defaults to [localhost](https://en.wikipedia.org/wiki/Localhost) and [private network](https://en.wikipedia.org/wiki/Private_network)." + } + ] + }, %{ group: :pleroma, key: :web_cache_ttl, diff --git a/docs/config.md b/docs/config.md index ed119fd32..262d15bba 100644 --- a/docs/config.md +++ b/docs/config.md @@ -730,6 +730,8 @@ This will probably take a long time. This is an advanced feature and disabled by default. +If your instance is behind a reverse proxy you must enable and configure [`Pleroma.Plugs.RemoteIp`](#pleroma-plugs-remoteip). + A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: * The first element: `scale` (Integer). The time scale in milliseconds. @@ -756,3 +758,16 @@ Available caches: * `:activity_pub` - activity pub routes (except question activities). Defaults to `nil` (no expiration). * `:activity_pub_question` - activity pub routes (question activities). Defaults to `30_000` (30 seconds). + +## Pleroma.Plugs.RemoteIp + +**If your instance is not behind at least one reverse proxy, you should not enable this plug.** + +`Pleroma.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration. + +Available options: + +* `enabled` - Enable/disable the plug. Defaults to `false`. +* `headers` - A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Defaults to `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`. +* `proxies` - A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Defaults to `[]`. +* `reserved` - Defaults to [localhost](https://en.wikipedia.org/wiki/Localhost) and [private network](https://en.wikipedia.org/wiki/Private_network). diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx index 4da9918ca..7f48b614b 100644 --- a/installation/pleroma.nginx +++ b/installation/pleroma.nginx @@ -70,6 +70,7 @@ server { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # this is explicitly IPv4 since Pleroma.Web.Endpoint binds on IPv4 only # and `localhost.` resolves to [::0] on some systems: see issue #930 diff --git a/lib/pleroma/plugs/remote_ip.ex b/lib/pleroma/plugs/remote_ip.ex new file mode 100644 index 000000000..fdedc27ee --- /dev/null +++ b/lib/pleroma/plugs/remote_ip.ex @@ -0,0 +1,54 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.RemoteIp do + @moduledoc """ + This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration. + """ + + @behaviour Plug + + @headers ~w[ + forwarded + x-forwarded-for + x-client-ip + x-real-ip + ] + + # https://en.wikipedia.org/wiki/Localhost + # https://en.wikipedia.org/wiki/Private_network + @reserved ~w[ + 127.0.0.0/8 + ::1/128 + fc00::/7 + 10.0.0.0/8 + 172.16.0.0/12 + 192.168.0.0/16 + ] + + def init(_), do: nil + + def call(conn, _) do + config = Pleroma.Config.get(__MODULE__, []) + + if Keyword.get(config, :enabled, false) do + RemoteIp.call(conn, remote_ip_opts(config)) + else + conn + end + end + + defp remote_ip_opts(config) do + headers = config |> Keyword.get(:headers, @headers) |> MapSet.new() + reserved = Keyword.get(config, :reserved, @reserved) + + proxies = + config + |> Keyword.get(:proxies, []) + |> Enum.concat(reserved) + |> Enum.map(&InetCidr.parse/1) + + {headers, proxies} + end +end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index eb805e853..2212e93f4 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -97,10 +97,7 @@ defmodule Pleroma.Web.Endpoint do extra: extra ) - # Note: the plug and its configuration is compile-time this can't be upstreamed yet - if proxies = Pleroma.Config.get([__MODULE__, :reverse_proxies]) do - plug(RemoteIp, proxies: proxies) - end + plug(Pleroma.Plugs.RemoteIp) defmodule Instrumenter do use Prometheus.PhoenixInstrumenter diff --git a/mix.exs b/mix.exs index 861b94ad0..3a605b455 100644 --- a/mix.exs +++ b/mix.exs @@ -159,6 +159,9 @@ defp deps do {:plug_static_index_html, "~> 1.0.0"}, {:excoveralls, "~> 0.11.1", only: :test}, {:flake_id, "~> 0.1.0"}, + {:remote_ip, + git: "https://git.pleroma.social/pleroma/remote_ip.git", + ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"}, {:mox, "~> 0.5", only: :test} ] ++ oauth_deps() end diff --git a/mix.lock b/mix.lock index 32443fb51..5f740638c 100644 --- a/mix.lock +++ b/mix.lock @@ -48,6 +48,7 @@ "http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]}, "httpoison": {:hex, :httpoison, "1.2.0", "2702ed3da5fd7a8130fc34b11965c8cfa21ade2f232c00b42d96d4967c39a3a3", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, + "inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "joken": {:hex, :joken, "2.0.1", "ec9ab31bf660f343380da033b3316855197c8d4c6ef597fa3fcb451b326beb14", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"}, "jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, @@ -87,6 +88,7 @@ "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, + "remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "825dc00aaba5a1b7c4202a532b696b595dd3bcb3", [ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"]}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"}, "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"}, diff --git a/test/plugs/remote_ip_test.exs b/test/plugs/remote_ip_test.exs new file mode 100644 index 000000000..d120c588b --- /dev/null +++ b/test/plugs/remote_ip_test.exs @@ -0,0 +1,72 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.RemoteIpTest do + use ExUnit.Case, async: true + use Plug.Test + + alias Pleroma.Plugs.RemoteIp + + test "disabled" do + Pleroma.Config.put(RemoteIp, enabled: false) + + %{remote_ip: remote_ip} = conn(:get, "/") + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == remote_ip + end + + test "enabled" do + Pleroma.Config.put(RemoteIp, enabled: true) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end + + test "custom headers" do + Pleroma.Config.put(RemoteIp, enabled: true, headers: ["cf-connecting-ip"]) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "1.1.1.1") + |> RemoteIp.call(nil) + + refute conn.remote_ip == {1, 1, 1, 1} + + conn = + conn(:get, "/") + |> put_req_header("cf-connecting-ip", "1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end + + test "custom proxies" do + Pleroma.Config.put(RemoteIp, enabled: true) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") + |> RemoteIp.call(nil) + + refute conn.remote_ip == {1, 1, 1, 1} + + Pleroma.Config.put([RemoteIp, :proxies], ["173.245.48.0/20"]) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end +end From 374f83d29b5793d75a3a6be7c18cf52cfed42b64 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 28 Sep 2019 01:56:20 +0300 Subject: [PATCH 248/272] Fix not being able to post empty statuses with attachments Attachment field was filled in after the empty status check --- lib/pleroma/web/common_api/activity_draft.ex | 2 +- .../controllers/status_controller_test.exs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index aa7c8c381..f7da81b34 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -40,11 +40,11 @@ def create(user, params) do |> put_params(params) |> status() |> summary() + |> with_valid(&attachments/1) |> full_payload() |> expires_at() |> poll() |> with_valid(&in_reply_to/1) - |> with_valid(&attachments/1) |> with_valid(&in_reply_to_conversation/1) |> with_valid(&visibility/1) |> content() diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index cbd4bafe8..c0121ac63 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -99,6 +99,28 @@ test "posting a status", %{conn: conn} do NaiveDateTime.to_iso8601(expiration.scheduled_at) end + test "posting an empty status with an attachment", %{conn: conn} do + user = insert(:user) + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/statuses", %{ + "media_ids" => [to_string(upload.id)], + "status" => "" + }) + + assert json_response(conn, 200) + end + test "replying to a status", %{conn: conn} do user = insert(:user) {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"}) From 9202904da9b48eb2a3884b8e89ea879e01d44b9a Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sat, 28 Sep 2019 01:21:28 +0200 Subject: [PATCH 249/272] status_controller.ex: Posting media status without content defined --- .../web/mastodon_api/controllers/status_controller.ex | 4 ++++ test/web/mastodon_api/controllers/status_controller_test.exs | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index f7da10289..ae3d51575 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -103,6 +103,10 @@ def create(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do end end + def create(%{assigns: %{user: _user}} = conn, %{"media_ids" => _} = params) do + create(conn, Map.put(params, "status", "")) + end + @doc "GET /api/v1/statuses/:id" def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{} = activity <- Activity.get_by_id_with_object(id), diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index c0121ac63..b194feae6 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -99,7 +99,7 @@ test "posting a status", %{conn: conn} do NaiveDateTime.to_iso8601(expiration.scheduled_at) end - test "posting an empty status with an attachment", %{conn: conn} do + test "posting an undefined status with an attachment", %{conn: conn} do user = insert(:user) file = %Plug.Upload{ @@ -114,8 +114,7 @@ test "posting an empty status with an attachment", %{conn: conn} do conn |> assign(:user, user) |> post("/api/v1/statuses", %{ - "media_ids" => [to_string(upload.id)], - "status" => "" + "media_ids" => [to_string(upload.id)] }) assert json_response(conn, 200) From 0e59d1dc04db64decc0c3bd47e3bf459cb768710 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 29 Sep 2019 00:01:35 +0300 Subject: [PATCH 250/272] Update admin_api.md --- docs/api/admin_api.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index fcdb33944..8795c2628 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -330,10 +330,10 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ### Get a list of reports - Method `GET` - Params: - - `state`: optional, the state of reports. Valid values are `open`, `closed` and `resolved` - - `limit`: optional, the number of records to retrieve - - `since_id`: optional, returns results that are more recent than the specified id - - `max_id`: optional, returns results that are older than the specified id + - *optional* `state`: **string** the state of reports. Valid values are `open`, `closed` and `resolved` + - *optional* `limit`: **integer** the number of records to retrieve + - *optional* `page`: **integer** page number + - *optional* `page_size`: **integer** number of log entries per page (default is `50`) - Response: - On failure: 403 Forbidden error `{"error": "error_msg"}` when requested by anonymous or non-admin - On success: JSON, returns a list of reports, where: From 51a4a211a3d1ac650e452a1ee9e9dd0d40040595 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 29 Sep 2019 02:13:17 +0200 Subject: [PATCH 251/272] CHANGELOG.md: !1691 is a breaking change !1691: https://git.pleroma.social/pleroma/pleroma/merge_requests/1691 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d307f0e1..71110622d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Admin API: Return `total` when querying for reports - Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) -- Admin API: Return link alongside with token on password reset +- **Breaking** Admin API: Return link alongside with token on password reset - Mastodon API: notifications no longer include subscription notifications - they are now served from new endpoints in Pleroma API ### Fixed - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) From 717cb4f9332a9cb71d6965ad9eea13861892881e Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 29 Sep 2019 02:14:53 +0200 Subject: [PATCH 252/272] admin_api.md: Put data-type info as the values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to how the other responses examples are done, this also makes it proper JSON (as it doesn’t have comments). --- docs/api/admin_api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 8795c2628..ee9e68cb1 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -312,8 +312,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ```json { - "token": "U13DX6muOvpRsj35_ij9wLxUbkU-eFvfKttxs6gIajo=", // password reset token (base64 string) - "link": "https://pleroma.social/api/pleroma/password_reset/U13DX6muOvpRsj35_ij9wLxUbkU-eFvfKttxs6gIajo%3D" + "token": "base64 reset token", + "link": "https://pleroma.social/api/pleroma/password_reset/url-encoded-base64-token" } ``` From e46dfd929548758cb99f8ea1bd7bf7e60b65833b Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 29 Sep 2019 02:16:52 +0200 Subject: [PATCH 253/272] CHANGELOG.md: Sorting, colon after breaking [ci skip] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71110622d..43a204be5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,11 +15,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) +- **Breaking:** Admin API: Return link alongside with token on password reset - Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Admin API: Return `total` when querying for reports - Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) -- **Breaking** Admin API: Return link alongside with token on password reset - Mastodon API: notifications no longer include subscription notifications - they are now served from new endpoints in Pleroma API ### Fixed - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) From e9d1aa75d5dc0859b692e891f6e65949208a5f0f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 29 Sep 2019 18:43:27 +0300 Subject: [PATCH 254/272] Revert subscription refactoring. As discussed in pleroma-meta#2 This reverts commit eb9aa7aa1095de150d036839c78c402019efb4b1, reversing changes made to c4fbb56984d8f86df948cfd9b0f7c081d688c365. --- CHANGELOG.md | 9 +- lib/pleroma/notification.ex | 1 + lib/pleroma/subscription_notification.ex | 260 ------------------ lib/pleroma/web/activity_pub/activity_pub.ex | 2 - .../subscription_notification_controller.ex | 71 ----- lib/pleroma/web/pleroma_api/pleroma_api.ex | 40 --- .../views/subscription_notification_view.ex | 61 ---- lib/pleroma/web/push/impl.ex | 3 +- lib/pleroma/web/router.ex | 8 - ...5028_create_subscription_notifications.exs | 15 - test/notification_test.exs | 12 +- test/web/mastodon_api/mastodon_api_test.exs | 4 +- ...scription_notification_controller_test.exs | 234 ---------------- .../pleroma_api_controller_test.exs | 0 14 files changed, 11 insertions(+), 709 deletions(-) delete mode 100644 lib/pleroma/subscription_notification.ex delete mode 100644 lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex delete mode 100644 lib/pleroma/web/pleroma_api/pleroma_api.ex delete mode 100644 lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex delete mode 100644 priv/repo/migrations/20190824195028_create_subscription_notifications.exs delete mode 100644 test/web/pleroma_api/controllers/subscription_notification_controller_test.exs rename test/web/pleroma_api/{controllers => }/pleroma_api_controller_test.exs (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index e859e318a..61323970a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Refreshing poll results for remote polls - Admin API: Add ability to require password reset -- Pleroma API: `GET /api/v1/pleroma/subscription_notifications/` to get list of subscription notifications -- Pleroma API: `GET /api/v1/pleroma/subscription_notifications/:id` to get a subscription notification -- Pleroma API: `POST /api/v1/pleroma/subscription_notifications/clear` to clear all subscription notifications -- Pleroma API: `POST /api/v1/pleroma/subscription_notifications/dismiss` to clear a subscription notification -- Pleroma API: `DELETE /api/v1/pleroma/subscription_notifications/destroy_multiple` to clear multiple subscription notifications -- Mastodon API: Account entities now include `follow_requests_count` (planned Mastodon 3.x addition) ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) @@ -21,7 +15,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Admin API: Return `total` when querying for reports - Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`) -- Mastodon API: notifications no longer include subscription notifications - they are now served from new endpoints in Pleroma API +- Admin API: Return link alongside with token on password reset + ### Fixed - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index d19924289..d94ae5971 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -230,6 +230,7 @@ def get_notified_from_activity( [] |> Utils.maybe_notify_to_recipients(activity) |> Utils.maybe_notify_mentioned_recipients(activity) + |> Utils.maybe_notify_subscribers(activity) |> Enum.uniq() User.get_users_from_set(recipients, local_only) diff --git a/lib/pleroma/subscription_notification.ex b/lib/pleroma/subscription_notification.ex deleted file mode 100644 index 1349d988c..000000000 --- a/lib/pleroma/subscription_notification.ex +++ /dev/null @@ -1,260 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.SubscriptionNotification do - use Ecto.Schema - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Pagination - alias Pleroma.Repo - alias Pleroma.SubscriptionNotification - alias Pleroma.User - alias Pleroma.Web.CommonAPI.Utils - alias Pleroma.Web.Push - alias Pleroma.Web.Streamer - - import Ecto.Query - import Ecto.Changeset - - @type t :: %__MODULE__{} - - schema "subscription_notifications" do - belongs_to(:user, User, type: FlakeId.Ecto.CompatType) - belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType) - - timestamps() - end - - def changeset(%SubscriptionNotification{} = notification, attrs) do - cast(notification, attrs, []) - end - - def for_user_query(user, opts \\ []) do - query = - SubscriptionNotification - |> where(user_id: ^user.id) - |> where( - [n, a], - fragment( - "? not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')", - a.actor - ) - ) - |> join(:inner, [n], activity in assoc(n, :activity)) - |> join(:left, [n, a], object in Object, - on: - fragment( - "(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)", - object.data, - a.data - ) - ) - |> preload([n, a, o], activity: {a, object: o}) - - if opts[:with_muted] do - query - else - query - |> where([n, a], a.actor not in ^user.info.muted_notifications) - |> where([n, a], a.actor not in ^user.info.blocks) - |> where( - [n, a], - fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks - ) - |> join(:left, [n, a], tm in Pleroma.ThreadMute, - on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data) - ) - |> where([n, a, o, tm], is_nil(tm.user_id)) - end - end - - def for_user(user, opts \\ %{}) do - user - |> for_user_query(opts) - |> Pagination.fetch_paginated(opts) - end - - @doc """ - Returns notifications for user received since given date. - - ## Examples - - iex> Pleroma.SubscriptionNotification.for_user_since(%Pleroma.User{}, ~N[2019-04-13 11:22:33]) - [%Pleroma.SubscriptionNotification{}, %Pleroma.SubscriptionNotification{}] - - iex> Pleroma.SubscriptionNotification.for_user_since(%Pleroma.User{}, ~N[2019-04-15 11:22:33]) - [] - """ - @spec for_user_since(Pleroma.User.t(), NaiveDateTime.t()) :: [t()] - def for_user_since(user, date) do - user - |> for_user_query() - |> where([n], n.updated_at > ^date) - |> Repo.all() - end - - def clear_up_to(%{id: user_id} = _user, id) do - from( - n in SubscriptionNotification, - where: n.user_id == ^user_id, - where: n.id <= ^id - ) - |> Repo.delete_all([]) - end - - def get(%{id: user_id} = _user, id) do - query = - from( - n in SubscriptionNotification, - where: n.id == ^id, - join: activity in assoc(n, :activity), - preload: [activity: activity] - ) - - case Repo.one(query) do - %{user_id: ^user_id} = notification -> - {:ok, notification} - - _ -> - {:error, "Cannot get notification"} - end - end - - def clear(user) do - from(n in SubscriptionNotification, where: n.user_id == ^user.id) - |> Repo.delete_all() - end - - def destroy_multiple(%{id: user_id} = _user, ids) do - from(n in SubscriptionNotification, - where: n.id in ^ids, - where: n.user_id == ^user_id - ) - |> Repo.delete_all() - end - - def dismiss(%{id: user_id} = _user, id) do - case Repo.get(SubscriptionNotification, id) do - %{user_id: ^user_id} = notification -> - Repo.delete(notification) - - _ -> - {:error, "Cannot dismiss notification"} - end - end - - def create_notifications(%Activity{data: %{"to" => _, "type" => "Create"}} = activity) do - case Object.normalize(activity) do - %{data: %{"type" => "Answer"}} -> - {:ok, []} - - _ -> - users = get_notified_from_activity(activity) - notifications = Enum.map(users, fn user -> create_notification(activity, user) end) - {:ok, notifications} - end - end - - def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity) - when type in ["Like", "Announce", "Follow"] do - notifications = - activity - |> get_notified_from_activity() - |> Enum.map(&create_notification(activity, &1)) - - {:ok, notifications} - end - - def create_notifications(_), do: {:ok, []} - - # TODO move to sql, too. - def create_notification(%Activity{} = activity, %User{} = user) do - unless skip?(activity, user) do - notification = %SubscriptionNotification{user_id: user.id, activity: activity} - {:ok, notification} = Repo.insert(notification) - Streamer.stream("user", notification) - Streamer.stream("user:subscription_notification", notification) - Push.send(notification) - notification - end - end - - def get_notified_from_activity(activity, local_only \\ true) - - def get_notified_from_activity( - %Activity{data: %{"to" => _, "type" => type} = _data} = activity, - local_only - ) - when type in ["Create", "Like", "Announce", "Follow"] do - [] - |> Utils.maybe_notify_subscribers(activity) - |> Enum.uniq() - |> User.get_users_from_set(local_only) - end - - def get_notified_from_activity(_, _local_only), do: [] - - @spec skip?(Activity.t(), User.t()) :: boolean() - def skip?(activity, user) do - [ - :self, - :followers, - :follows, - :non_followers, - :non_follows, - :recently_followed - ] - |> Enum.any?(&skip?(&1, activity, user)) - end - - @spec skip?(atom(), Activity.t(), User.t()) :: boolean() - def skip?(:self, activity, user) do - activity.data["actor"] == user.ap_id - end - - def skip?( - :followers, - %{data: %{"actor" => actor}}, - %{info: %{notification_settings: %{"followers" => false}}} = user - ) do - actor - |> User.get_cached_by_ap_id() - |> User.following?(user) - end - - def skip?( - :non_followers, - activity, - %{info: %{notification_settings: %{"non_followers" => false}}} = user - ) do - actor = activity.data["actor"] - follower = User.get_cached_by_ap_id(actor) - !User.following?(follower, user) - end - - def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do - actor = activity.data["actor"] - followed = User.get_cached_by_ap_id(actor) - User.following?(user, followed) - end - - def skip?( - :non_follows, - activity, - %{info: %{notification_settings: %{"non_follows" => false}}} = user - ) do - actor = activity.data["actor"] - followed = User.get_cached_by_ap_id(actor) - !User.following?(user, followed) - end - - def skip?(:recently_followed, %{data: %{"type" => "Follow", "actor" => actor}}, user) do - user - |> SubscriptionNotification.for_user() - |> Enum.any?(&match?(%{activity: %{data: %{"type" => "Follow", "actor" => ^actor}}}, &1)) - end - - def skip?(_, _, _), do: false -end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 7e83e27e5..8d0a57623 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Object.Fetcher alias Pleroma.Pagination alias Pleroma.Repo - alias Pleroma.SubscriptionNotification alias Pleroma.Upload alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF @@ -152,7 +151,6 @@ def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when BackgroundWorker.enqueue("fetch_data_for_activity", %{"activity_id" => activity.id}) Notification.create_notifications(activity) - SubscriptionNotification.create_notifications(activity) participations = activity diff --git a/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex b/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex deleted file mode 100644 index 37c2222de..000000000 --- a/lib/pleroma/web/pleroma_api/controllers/subscription_notification_controller.ex +++ /dev/null @@ -1,71 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationController do - use Pleroma.Web, :controller - - import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] - - alias Pleroma.Activity - alias Pleroma.SubscriptionNotification - alias Pleroma.User - alias Pleroma.Web.PleromaAPI.PleromaAPI - - def index(%{assigns: %{user: user}} = conn, params) do - notifications = - user - |> PleromaAPI.get_subscription_notifications(params) - |> Enum.map(&build_notification_data/1) - - conn - |> add_link_headers(notifications) - |> render("index.json", %{notifications: notifications, for: user}) - end - - def show(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do - with {:ok, notification} <- SubscriptionNotification.get(user, id) do - render(conn, "show.json", %{ - subscription_notification: build_notification_data(notification), - for: user - }) - else - {:error, reason} -> - conn - |> put_status(:forbidden) - |> json(%{"error" => reason}) - end - end - - def clear(%{assigns: %{user: user}} = conn, _params) do - SubscriptionNotification.clear(user) - json(conn, %{}) - end - - def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do - with {:ok, _notif} <- SubscriptionNotification.dismiss(user, id) do - json(conn, %{}) - else - {:error, reason} -> - conn - |> put_status(:forbidden) - |> json(%{"error" => reason}) - end - end - - def destroy_multiple( - %{assigns: %{user: user}} = conn, - %{"ids" => ids} = _params - ) do - SubscriptionNotification.destroy_multiple(user, ids) - json(conn, %{}) - end - - defp build_notification_data(%{activity: %{data: data}} = notification) do - %{ - notification: notification, - actor: User.get_cached_by_ap_id(data["actor"]), - parent_activity: Activity.get_create_by_object_ap_id(data["object"]) - } - end -end diff --git a/lib/pleroma/web/pleroma_api/pleroma_api.ex b/lib/pleroma/web/pleroma_api/pleroma_api.ex deleted file mode 100644 index 480964845..000000000 --- a/lib/pleroma/web/pleroma_api/pleroma_api.ex +++ /dev/null @@ -1,40 +0,0 @@ -defmodule Pleroma.Web.PleromaAPI.PleromaAPI do - import Ecto.Query - import Ecto.Changeset - - alias Pleroma.Activity - alias Pleroma.Pagination - alias Pleroma.SubscriptionNotification - - def get_subscription_notifications(user, params \\ %{}) do - options = cast_params(params) - - user - |> SubscriptionNotification.for_user_query(options) - |> restrict(:exclude_types, options) - |> Pagination.fetch_paginated(params) - end - - defp cast_params(params) do - param_types = %{ - exclude_types: {:array, :string}, - reblogs: :boolean, - with_muted: :boolean - } - - changeset = cast({%{}, param_types}, params, Map.keys(param_types)) - changeset.changes - end - - defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]}) do - ap_types = - mastodon_types - |> Enum.map(&Activity.from_mastodon_notification_type/1) - |> Enum.filter(& &1) - - query - |> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data)) - end - - defp restrict(query, _, _), do: query -end diff --git a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex b/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex deleted file mode 100644 index fc41a7389..000000000 --- a/lib/pleroma/web/pleroma_api/views/subscription_notification_view.ex +++ /dev/null @@ -1,61 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationView do - use Pleroma.Web, :view - - alias Pleroma.Activity - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.AccountView - alias Pleroma.Web.MastodonAPI.StatusView - alias Pleroma.Web.PleromaAPI.SubscriptionNotificationView - - def render("index.json", %{notifications: notifications, for: user}) do - safe_render_many(notifications, SubscriptionNotificationView, "show.json", %{for: user}) - end - - def render("show.json", %{ - subscription_notification: %{ - notification: %{activity: activity} = notification, - actor: actor, - parent_activity: parent_activity - }, - for: user - }) do - mastodon_type = Activity.mastodon_notification_type(activity) - - response = %{ - id: to_string(notification.id), - type: mastodon_type, - created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at), - account: AccountView.render("account.json", %{user: actor, for: user}) - } - - case mastodon_type do - "mention" -> - response - |> Map.merge(%{ - status: StatusView.render("show.json", %{activity: activity, for: user}) - }) - - "favourite" -> - response - |> Map.merge(%{ - status: StatusView.render("show.json", %{activity: parent_activity, for: user}) - }) - - "reblog" -> - response - |> Map.merge(%{ - status: StatusView.render("show.json", %{activity: parent_activity, for: user}) - }) - - "follow" -> - response - - _ -> - nil - end - end -end diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index 7ea5607fa..35d3ff07c 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -9,7 +9,6 @@ defmodule Pleroma.Web.Push.Impl do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo - alias Pleroma.SubscriptionNotification alias Pleroma.User alias Pleroma.Web.Metadata.Utils alias Pleroma.Web.Push.Subscription @@ -20,7 +19,7 @@ defmodule Pleroma.Web.Push.Impl do @types ["Create", "Follow", "Announce", "Like"] @doc "Performs sending notifications for user subscriptions" - @spec perform(Notification.t() | SubscriptionNotification.t()) :: list(any) | :error + @spec perform(Notification.t()) :: list(any) | :error def perform( %{ activity: %{data: %{"type" => activity_type}, id: activity_id} = activity, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a025474e2..805bef16f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -293,14 +293,6 @@ defmodule Pleroma.Web.Router do pipe_through(:oauth_read) get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) get("/conversations/:id", PleromaAPIController, :conversation) - - scope "/subscription_notifications" do - post("/clear", SubscriptionNotificationController, :clear) - post("/dismiss", SubscriptionNotificationController, :dismiss) - delete("/destroy_multiple", SubscriptionNotificationController, :destroy_multiple) - get("/", SubscriptionNotificationController, :index) - get("/:id", SubscriptionNotificationController, :show) - end end scope [] do diff --git a/priv/repo/migrations/20190824195028_create_subscription_notifications.exs b/priv/repo/migrations/20190824195028_create_subscription_notifications.exs deleted file mode 100644 index fcceb4386..000000000 --- a/priv/repo/migrations/20190824195028_create_subscription_notifications.exs +++ /dev/null @@ -1,15 +0,0 @@ -defmodule Pleroma.Repo.Migrations.CreateSubscriptionNotifications do - use Ecto.Migration - - def change do - create_if_not_exists table(:subscription_notifications) do - add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) - add(:activity_id, references(:activities, type: :uuid, on_delete: :delete_all)) - - timestamps() - end - - create_if_not_exists(index(:subscription_notifications, [:user_id])) - create_if_not_exists(index(:subscription_notifications, ["id desc nulls last"])) - end -end diff --git a/test/notification_test.exs b/test/notification_test.exs index 1dbad34c1..54c0f9877 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -33,16 +33,16 @@ test "notifies someone when they are directly addressed" do assert other_notification.activity_id == activity.id end - test "it does not create a notification for subscribed users" do + test "it creates a notification for subscribed users" do user = insert(:user) subscriber = insert(:user) User.subscribe(subscriber, user) {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"}) - {:ok, notifications} = Notification.create_notifications(status) + {:ok, [notification]} = Notification.create_notifications(status) - assert notifications == [] + assert notification.user_id == subscriber.id end test "does not create a notification for subscribed users if status is a reply" do @@ -182,16 +182,14 @@ test "it doesn't create a notification for follow-unfollow-follow chains" do refute Notification.create_notification(activity_dupe, followed_user) end - test "it doesn't create notifications for follow+subscribed users" do + test "it doesn't create duplicate notifications for follow+subscribed users" do user = insert(:user) subscriber = insert(:user) {:ok, _, _, _} = CommonAPI.follow(subscriber, user) User.subscribe(subscriber, user) {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"}) - {:ok, notifications} = Notification.create_notifications(status) - - assert notifications == [] + {:ok, [_notif]} = Notification.create_notifications(status) end test "it doesn't create subscription notifications if the recipient cannot see the status" do diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/web/mastodon_api/mastodon_api_test.exs index 848fce7ad..7fcb2bd55 100644 --- a/test/web/mastodon_api/mastodon_api_test.exs +++ b/test/web/mastodon_api/mastodon_api_test.exs @@ -75,9 +75,9 @@ test "returns notifications for user" do User.subscribe(subscriber, user) - {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin @#{subscriber.nickname}"}) + {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"}) - {:ok, status1} = CommonAPI.post(user, %{"status" => "Magi @#{subscriber.nickname}"}) + {:ok, status1} = CommonAPI.post(user, %{"status" => "Magi"}) {:ok, [notification]} = Notification.create_notifications(status) {:ok, [notification1]} = Notification.create_notifications(status1) res = MastodonAPI.get_notifications(subscriber) diff --git a/test/web/pleroma_api/controllers/subscription_notification_controller_test.exs b/test/web/pleroma_api/controllers/subscription_notification_controller_test.exs deleted file mode 100644 index c6a71732d..000000000 --- a/test/web/pleroma_api/controllers/subscription_notification_controller_test.exs +++ /dev/null @@ -1,234 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.SubscriptionNotificationControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Repo - alias Pleroma.SubscriptionNotification - alias Pleroma.User - alias Pleroma.Web.CommonAPI - import Pleroma.Factory - import Tesla.Mock - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - clear_config([:instance, :public]) - clear_config([:rich_media, :enabled]) - - describe "subscription_notifications" do - setup do - user = insert(:user) - subscriber = insert(:user) - - User.subscribe(subscriber, user) - - {:ok, %{user: user, subscriber: subscriber}} - end - - test "list of notifications", %{conn: conn, user: user, subscriber: subscriber} do - status_text = "Hello" - {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) - path = subscription_notification_path(conn, :index) - - conn = - conn - |> assign(:user, subscriber) - |> get(path) - - assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) - assert response == status_text - end - - test "getting a single notification", %{conn: conn, user: user, subscriber: subscriber} do - status_text = "Hello" - - {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) - [notification] = Repo.all(SubscriptionNotification) - - path = subscription_notification_path(conn, :show, notification) - - conn = - conn - |> assign(:user, subscriber) - |> get(path) - - assert %{"status" => %{"content" => response}} = json_response(conn, 200) - assert response == status_text - end - - test "dismissing a single notification also deletes it", %{ - conn: conn, - user: user, - subscriber: subscriber - } do - status_text = "Hello" - {:ok, _activity} = CommonAPI.post(user, %{"status" => status_text}) - - [notification] = Repo.all(SubscriptionNotification) - - conn = - conn - |> assign(:user, subscriber) - |> post(subscription_notification_path(conn, :dismiss), %{"id" => notification.id}) - - assert %{} = json_response(conn, 200) - - assert Repo.all(SubscriptionNotification) == [] - end - - test "clearing all notifications also deletes them", %{ - conn: conn, - user: user, - subscriber: subscriber - } do - status_text1 = "Hello" - status_text2 = "Hello again" - {:ok, _activity1} = CommonAPI.post(user, %{"status" => status_text1}) - {:ok, _activity2} = CommonAPI.post(user, %{"status" => status_text2}) - - conn = - conn - |> assign(:user, subscriber) - |> post(subscription_notification_path(conn, :clear)) - - assert %{} = json_response(conn, 200) - - conn = - build_conn() - |> assign(:user, subscriber) - |> get(subscription_notification_path(conn, :index)) - - assert json_response(conn, 200) == [] - - assert Repo.all(SubscriptionNotification) == [] - end - - test "paginates notifications using min_id, since_id, max_id, and limit", %{ - conn: conn, - user: user, - subscriber: subscriber - } do - {:ok, activity1} = CommonAPI.post(user, %{"status" => "Hello 1"}) - {:ok, activity2} = CommonAPI.post(user, %{"status" => "Hello 2"}) - {:ok, activity3} = CommonAPI.post(user, %{"status" => "Hello 3"}) - {:ok, activity4} = CommonAPI.post(user, %{"status" => "Hello 4"}) - - notification1_id = - Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() - - notification2_id = - Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() - - notification3_id = - Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() - - notification4_id = - Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() - - conn = assign(conn, :user, subscriber) - - # min_id - conn_res = - get( - conn, - subscription_notification_path(conn, :index, %{ - "limit" => 2, - "min_id" => notification1_id - }) - ) - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - - # since_id - conn_res = - get( - conn, - subscription_notification_path(conn, :index, %{ - "limit" => 2, - "since_id" => notification1_id - }) - ) - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - - # max_id - conn_res = - get( - conn, - subscription_notification_path(conn, :index, %{ - "limit" => 2, - "max_id" => notification4_id - }) - ) - - result = json_response(conn_res, 200) - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - end - - test "destroy multiple", %{conn: conn, user: user1, subscriber: user2} do - # mutual subscription - User.subscribe(user1, user2) - - {:ok, activity1} = CommonAPI.post(user1, %{"status" => "Hello 1"}) - {:ok, activity2} = CommonAPI.post(user1, %{"status" => "World 1"}) - {:ok, activity3} = CommonAPI.post(user2, %{"status" => "Hello 2"}) - {:ok, activity4} = CommonAPI.post(user2, %{"status" => "World 2"}) - - notification1_id = - Repo.get_by(SubscriptionNotification, activity_id: activity1.id).id |> to_string() - - notification2_id = - Repo.get_by(SubscriptionNotification, activity_id: activity2.id).id |> to_string() - - notification3_id = - Repo.get_by(SubscriptionNotification, activity_id: activity3.id).id |> to_string() - - notification4_id = - Repo.get_by(SubscriptionNotification, activity_id: activity4.id).id |> to_string() - - conn = assign(conn, :user, user1) - - conn_res = get(conn, subscription_notification_path(conn, :index)) - - result = json_response(conn_res, 200) - - Enum.each(result, fn %{"id" => id} -> - assert id in [notification3_id, notification4_id] - end) - - conn2 = assign(conn, :user, user2) - - conn_res = get(conn2, subscription_notification_path(conn, :index)) - - result = json_response(conn_res, 200) - - Enum.each(result, fn %{"id" => id} -> - assert id in [notification1_id, notification2_id] - end) - - conn_destroy = - delete(conn, subscription_notification_path(conn, :destroy_multiple), %{ - "ids" => [notification3_id, notification4_id] - }) - - assert json_response(conn_destroy, 200) == %{} - - conn_res = get(conn2, subscription_notification_path(conn, :index)) - - result = json_response(conn_res, 200) - - Enum.each(result, fn %{"id" => id} -> - assert id in [notification1_id, notification2_id] - end) - - assert length(Repo.all(SubscriptionNotification)) == 2 - end - end -end diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/pleroma_api_controller_test.exs similarity index 100% rename from test/web/pleroma_api/controllers/pleroma_api_controller_test.exs rename to test/web/pleroma_api/pleroma_api_controller_test.exs From 81b4243173f31fd47eb598fb7ed95cadadf90c2f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 29 Sep 2019 23:52:40 +0300 Subject: [PATCH 255/272] Remove subscription_notifications table if it existed Followup to !1741 --- ...0190929201536_drop_subscription_if_exists.exs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 priv/repo/migrations/20190929201536_drop_subscription_if_exists.exs diff --git a/priv/repo/migrations/20190929201536_drop_subscription_if_exists.exs b/priv/repo/migrations/20190929201536_drop_subscription_if_exists.exs new file mode 100644 index 000000000..bbf70f78b --- /dev/null +++ b/priv/repo/migrations/20190929201536_drop_subscription_if_exists.exs @@ -0,0 +1,16 @@ +defmodule Pleroma.Repo.Migrations.DropSubscriptionIfExists do + use Ecto.Migration + + def change do + + end + + def up do + drop_if_exists(index(:subscription_notifications, [:user_id])) + drop_if_exists(index(:subscription_notifications, ["id desc nulls last"])) + drop_if_exists(table(:subscription_notifications)) + end + def down do + :ok + end +end From d4d88b3361ea57d763c5093470b7ebaee6bcf11c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 30 Sep 2019 16:52:07 +0700 Subject: [PATCH 256/272] Extract conversation actions from `MastodonAPIController` to ConversationController --- .../controllers/conversation_controller.ex | 32 ++++++++ .../controllers/mastodon_api_controller.ex | 27 ------- .../mastodon_api/views/conversation_view.ex | 21 ++---- lib/pleroma/web/router.ex | 4 +- .../conversation_controller_test.exs | 75 +++++++++++++++++++ .../mastodon_api_controller_test.exs | 63 ---------------- 6 files changed, 116 insertions(+), 106 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex create mode 100644 test/web/mastodon_api/controllers/conversation_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex b/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex new file mode 100644 index 000000000..ea1e36a12 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ConversationController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + + alias Pleroma.Conversation.Participation + alias Pleroma.Repo + + action_fallback(Pleroma.Web.MastodonAPI.FallbackController) + + @doc "GET /api/v1/conversations" + def index(%{assigns: %{user: user}} = conn, params) do + participations = Participation.for_user_with_last_activity_id(user, params) + + conn + |> add_link_headers(participations) + |> render("participations.json", participations: participations, for: user) + end + + @doc "POST /api/v1/conversations/:id/read" + def read(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do + with %Participation{} = participation <- + Repo.get_by(Participation, id: participation_id, user_id: user.id), + {:ok, participation} <- Participation.mark_as_read(participation) do + render(conn, "participation.json", participation: participation, for: user) + end + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 0878f7ba6..650fb74cd 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -12,7 +12,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Activity alias Pleroma.Bookmark alias Pleroma.Config - alias Pleroma.Conversation.Participation alias Pleroma.Emoji alias Pleroma.HTTP alias Pleroma.Object @@ -27,7 +26,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.AppView - alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI alias Pleroma.Web.MastodonAPI.MastodonView @@ -1003,31 +1001,6 @@ def account_register(conn, _) do render_error(conn, :forbidden, "Invalid credentials") end - def conversations(%{assigns: %{user: user}} = conn, params) do - participations = Participation.for_user_with_last_activity_id(user, params) - - conversations = - Enum.map(participations, fn participation -> - ConversationView.render("participation.json", %{participation: participation, for: user}) - end) - - conn - |> add_link_headers(participations) - |> json(conversations) - end - - def conversation_read(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do - with %Participation{} = participation <- - Repo.get_by(Participation, id: participation_id, user_id: user.id), - {:ok, participation} <- Participation.mark_as_read(participation) do - participation_view = - ConversationView.render("participation.json", %{participation: participation, for: user}) - - conn - |> json(participation_view) - end - end - def password_reset(conn, params) do nickname_or_email = params["email"] || params["nickname"] diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index 4aeb79d81..2c5767dd8 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -11,6 +11,10 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.StatusView + def render("participations.json", %{participations: participations, for: user}) do + render_many(participations, __MODULE__, "participation.json", as: :participation, for: user) + end + def render("participation.json", %{participation: participation, for: user}) do participation = Repo.preload(participation, conversation: [], recipients: []) @@ -23,25 +27,14 @@ def render("participation.json", %{participation: participation, for: user}) do end activity = Activity.get_by_id_with_object(last_activity_id) - - last_status = StatusView.render("show.json", %{activity: activity, for: user}) - # Conversations return all users except the current user. - users = - participation.recipients - |> Enum.reject(&(&1.id == user.id)) - - accounts = - AccountView.render("accounts.json", %{ - users: users, - as: :user - }) + users = Enum.reject(participation.recipients, &(&1.id == user.id)) %{ id: participation.id |> to_string(), - accounts: accounts, + accounts: render(AccountView, "accounts.json", users: users, as: :user), unread: !participation.read, - last_status: last_status + last_status: render(StatusView, "show.json", activity: activity, for: user) } end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 805bef16f..5dafa3693 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -344,8 +344,8 @@ defmodule Pleroma.Web.Router do get("/suggestions", MastodonAPIController, :suggestions) - get("/conversations", MastodonAPIController, :conversations) - post("/conversations/:id/read", MastodonAPIController, :conversation_read) + get("/conversations", ConversationController, :index) + post("/conversations/:id/read", ConversationController, :read) get("/endorsements", MastodonAPIController, :empty_array) end diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/web/mastodon_api/controllers/conversation_controller_test.exs new file mode 100644 index 000000000..7117fc76a --- /dev/null +++ b/test/web/mastodon_api/controllers/conversation_controller_test.exs @@ -0,0 +1,75 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.User + alias Pleroma.Web.CommonAPI + + import Pleroma.Factory + + test "Conversations", %{conn: conn} do + user_one = insert(:user) + user_two = insert(:user) + user_three = insert(:user) + + {:ok, user_two} = User.follow(user_two, user_one) + + {:ok, direct} = + CommonAPI.post(user_one, %{ + "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!", + "visibility" => "direct" + }) + + {:ok, _follower_only} = + CommonAPI.post(user_one, %{ + "status" => "Hi @#{user_two.nickname}!", + "visibility" => "private" + }) + + res_conn = + conn + |> assign(:user, user_one) + |> get("/api/v1/conversations") + + assert response = json_response(res_conn, 200) + + assert [ + %{ + "id" => res_id, + "accounts" => res_accounts, + "last_status" => res_last_status, + "unread" => unread + } + ] = response + + account_ids = Enum.map(res_accounts, & &1["id"]) + assert length(res_accounts) == 2 + assert user_two.id in account_ids + assert user_three.id in account_ids + assert is_binary(res_id) + assert unread == true + assert res_last_status["id"] == direct.id + + # Apparently undocumented API endpoint + res_conn = + conn + |> assign(:user, user_one) + |> post("/api/v1/conversations/#{res_id}/read") + + assert response = json_response(res_conn, 200) + assert length(response["accounts"]) == 2 + assert response["last_status"]["id"] == direct.id + assert response["unread"] == false + + # (vanilla) Mastodon frontend behaviour + res_conn = + conn + |> assign(:user, user_one) + |> get("/api/v1/statuses/#{res_last_status["id"]}/context") + + assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200) + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b3acb7a22..8080d3941 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -33,69 +33,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do clear_config([:instance, :public]) clear_config([:rich_media, :enabled]) - test "Conversations", %{conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - user_three = insert(:user) - - {:ok, user_two} = User.follow(user_two, user_one) - - {:ok, direct} = - CommonAPI.post(user_one, %{ - "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!", - "visibility" => "direct" - }) - - {:ok, _follower_only} = - CommonAPI.post(user_one, %{ - "status" => "Hi @#{user_two.nickname}!", - "visibility" => "private" - }) - - res_conn = - conn - |> assign(:user, user_one) - |> get("/api/v1/conversations") - - assert response = json_response(res_conn, 200) - - assert [ - %{ - "id" => res_id, - "accounts" => res_accounts, - "last_status" => res_last_status, - "unread" => unread - } - ] = response - - account_ids = Enum.map(res_accounts, & &1["id"]) - assert length(res_accounts) == 2 - assert user_two.id in account_ids - assert user_three.id in account_ids - assert is_binary(res_id) - assert unread == true - assert res_last_status["id"] == direct.id - - # Apparently undocumented API endpoint - res_conn = - conn - |> assign(:user, user_one) - |> post("/api/v1/conversations/#{res_id}/read") - - assert response = json_response(res_conn, 200) - assert length(response["accounts"]) == 2 - assert response["last_status"]["id"] == direct.id - assert response["unread"] == false - - # (vanilla) Mastodon frontend behaviour - res_conn = - conn - |> assign(:user, user_one) - |> get("/api/v1/statuses/#{res_last_status["id"]}/context") - - assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200) - end - test "verify_credentials", %{conn: conn} do user = insert(:user) From 5fd29edac47de145fb7025a99137a69072dca3bb Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 27 Sep 2019 11:04:52 +0000 Subject: [PATCH 257/272] docs: add scrobble API description --- docs/api/pleroma_api.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index ac5489aa3..183cf8a28 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -439,3 +439,33 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * Params: None * Response: the archive of the pack with a 200 status code, 403 if the pack is not set as shared, 404 if the pack does not exist + +## `GET /api/v1/pleroma/accounts/:uid/now-playing` +### Requests a list of current and recent Listen activities for an account +* Method `GET` +* Authentication: not required +* Params: None +* Response: An array of media metadata entities. +* Example response: +```json +[ + { + "id": "1234", + "title": "Some Title", + "artist": "Some Artist", + "album": "Some Album", + "length": 180000 + } +] +``` + +## `POST /api/v1/pleroma/now-playing` +### Creates a new Listen activity for an account +* Method `POST` +* Authentication: required +* Params: + * `title`: the title of the media playing + * `album`: the album of the media playing [optional] + * `artist`: the artist of the media playing [optional] + * `length`: the length of the media playing [optional] +* Response: the newly created media metadata entity representing the Listen activity From c3d09921e4dd13f02ab141bba9ba8372f70bab76 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 27 Sep 2019 11:15:20 +0000 Subject: [PATCH 258/272] test: factory: implement support for generating mock audio and listen objects --- test/support/factory.ex | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/support/factory.ex b/test/support/factory.ex index 719115003..4f3244025 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -71,6 +71,47 @@ def note_factory(attrs \\ %{}) do } end + def audio_factory(attrs \\ %{}) do + text = sequence(:text, &"lain radio episode #{&1}") + + user = attrs[:user] || insert(:user) + + data = %{ + "type" => "Audio", + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), + "artist" => "lain", + "title" => text, + "album" => "lain radio", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "published" => DateTime.utc_now() |> DateTime.to_iso8601(), + "actor" => user.ap_id, + "length" => 180_000 + } + + %Pleroma.Object{ + data: merge_attributes(data, Map.get(attrs, :data, %{})) + } + end + + def listen_factory do + audio = insert(:audio) + + data = %{ + "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), + "type" => "Listen", + "actor" => audio.data["actor"], + "to" => audio.data["to"], + "object" => audio.data, + "published" => audio.data["published"] + } + + %Pleroma.Activity{ + data: data, + actor: data["actor"], + recipients: data["to"] + } + end + def direct_note_factory do user2 = insert(:user) From b7877e9b1c61e42d60bb65deef0cec7f1103dd89 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 27 Sep 2019 11:40:40 +0000 Subject: [PATCH 259/272] mastodon api: implement rendering of listen activities --- .../web/mastodon_api/views/status_view.ex | 17 +++++++++++++++++ .../web/mastodon_api/views/status_view_test.exs | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 2321d0de2..cf024a83c 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -368,6 +368,23 @@ def render("attachment.json", %{attachment: attachment}) do } end + def render("listen.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do + object = Object.normalize(activity) + + user = get_user(activity.data["actor"]) + created_at = Utils.to_masto_date(activity.data["published"]) + + %{ + id: activity.id, + account: AccountView.render("account.json", %{user: user, for: opts[:for]}), + created_at: created_at, + title: object.data["title"] |> HTML.strip_tags(), + artist: object.data["artist"] |> HTML.strip_tags(), + album: object.data["album"] |> HTML.strip_tags(), + length: object.data["length"] + } + end + def render("poll.json", %{object: object} = opts) do {multiple, options} = case object.data do diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index c17d0ef95..683132f8d 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -608,4 +608,13 @@ test "visibility/list" do assert status.visibility == "list" end + + test "successfully renders a Listen activity (pleroma extension)" do + listen_activity = insert(:listen) + + status = StatusView.render("listen.json", activity: listen_activity) + + assert status.length == listen_activity.data["object"]["length"] + assert status.title == listen_activity.data["object"]["title"] + end end From 1f9de2a8cdc1913b26afab1f914aea526db608d8 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 27 Sep 2019 12:22:35 +0000 Subject: [PATCH 260/272] activitypub: implement IR-level considerations for Listen activities --- lib/pleroma/web/activity_pub/activity_pub.ex | 20 +++++++++++ lib/pleroma/web/activity_pub/utils.ex | 17 ++++++++- test/web/activity_pub/activity_pub_test.exs | 36 ++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8d0a57623..425073541 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -248,6 +248,26 @@ def create(%{to: to, actor: actor, context: context, object: object} = params, f end end + def listen(%{to: to, actor: actor, context: context, object: object} = params) do + additional = params[:additional] || %{} + # only accept false as false value + local = !(params[:local] == false) + published = params[:published] + + with listen_data <- + make_listen_data( + %{to: to, actor: actor, published: published, context: context, object: object}, + additional + ), + {:ok, activity} <- insert(listen_data, local), + :ok <- maybe_federate(activity) do + {:ok, activity} + else + {:error, message} -> + {:error, message} + end + end + def accept(%{to: to, actor: actor, object: object} = params) do # only accept false as false value local = !(params[:local] == false) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 30628a793..2ba182f4e 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do require Logger require Pleroma.Constants - @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"] + @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer", "Audio"] @supported_report_states ~w(open closed resolved) @valid_visibilities ~w(public unlisted private direct) @@ -581,6 +581,21 @@ def make_create_data(params, additional) do |> Map.merge(additional) end + #### Listen-related helpers + def make_listen_data(params, additional) do + published = params.published || make_date() + + %{ + "type" => "Listen", + "to" => params.to |> Enum.uniq(), + "actor" => params.actor.ap_id, + "object" => params.object, + "published" => published, + "context" => params.context + } + |> Map.merge(additional) + end + #### Flag-related helpers @spec make_flag_data(map(), map()) :: map() def make_flag_data(%{actor: actor, context: context, content: content} = params, additional) do diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index f28fd6871..a203d1d30 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -257,6 +257,42 @@ test "adds an id to a given object if it lacks one and is a note and inserts it end end + describe "listen activities" do + test "does not increase user note count" do + user = insert(:user) + + {:ok, activity} = + ActivityPub.listen(%{ + to: ["https://www.w3.org/ns/activitystreams#Public"], + actor: user, + context: "", + object: %{ + "actor" => user.ap_id, + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "artist" => "lain", + "title" => "lain radio episode 1", + "length" => 180_000, + "type" => "Audio" + } + }) + + assert activity.actor == user.ap_id + + user = User.get_cached_by_id(user.id) + assert user.info.note_count == 0 + end + + test "can be fetched into a timeline" do + _listen_activity_1 = insert(:listen) + _listen_activity_2 = insert(:listen) + _listen_activity_3 = insert(:listen) + + timeline = ActivityPub.fetch_activities([], %{"type" => ["Listen"]}) + + assert length(timeline) == 3 + end + end + describe "create activities" do test "removes doubled 'to' recipients" do user = insert(:user) From 172c74a77baf5b8910987e19c620158d0497d16a Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 27 Sep 2019 12:40:31 +0000 Subject: [PATCH 261/272] activitypub: transmogrifier: implement support for Listen activities --- .../web/activity_pub/transmogrifier.ex | 33 ++++++++++++++++++- test/web/activity_pub/transmogrifier_test.exs | 29 ++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index dad2fead8..63877248a 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -430,6 +430,36 @@ def handle_incoming( end end + def handle_incoming( + %{"type" => "Listen", "object" => %{"type" => "Audio"} = object} = data, + options + ) do + actor = Containment.get_actor(data) + + data = + Map.put(data, "actor", actor) + |> fix_addressing + + with {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do + options = Keyword.put(options, :depth, (options[:depth] || 0) + 1) + object = fix_object(object, options) + + params = %{ + to: data["to"], + object: object, + actor: user, + context: nil, + local: false, + published: data["published"], + additional: Map.take(data, ["cc", "id"]) + } + + ActivityPub.listen(params) + else + _e -> :error + end + end + def handle_incoming( %{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data, _options @@ -765,7 +795,8 @@ def prepare_object(object) do # internal -> Mastodon # """ - def prepare_outgoing(%{"type" => "Create", "object" => object_id} = data) do + def prepare_outgoing(%{"type" => activity_type, "object" => object_id} = data) + when activity_type in ["Create", "Listen"] do object = object_id |> Object.normalize() diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index a35db71dc..9040c87ca 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -177,6 +177,35 @@ test "it works for incoming questions" do end) end + test "it works for incoming listens" do + data = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Listen", + "id" => "http://mastodon.example.org/users/admin/listens/1234/activity", + "actor" => "http://mastodon.example.org/users/admin", + "object" => %{ + "type" => "Audio", + "id" => "http://mastodon.example.org/users/admin/listens/1234", + "attributedTo" => "http://mastodon.example.org/users/admin", + "title" => "lain radio episode 1", + "artist" => "lain", + "album" => "lain radio", + "length" => 180_000 + } + } + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + object = Object.normalize(activity) + + assert object.data["title"] == "lain radio episode 1" + assert object.data["artist"] == "lain" + assert object.data["album"] == "lain radio" + assert object.data["length"] == 180_000 + end + test "it rewrites Note votes to Answers and increments vote counters on question activities" do user = insert(:user) From 2c82d8603bb4c3f7281023752dc78aa31a814ab6 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 28 Sep 2019 00:24:32 +0000 Subject: [PATCH 262/272] common api: implement scrobbling --- lib/pleroma/web/common_api/common_api.ex | 18 +++++++++++ test/web/common_api/common_api_test.exs | 39 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index a00e4b0d8..a040a6ce2 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -212,6 +212,24 @@ def check_expiry_date(expiry_str) do |> check_expiry_date() end + def listen(user, %{"title" => _} = data) do + with visibility <- data["visibility"] || "public", + {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil), + listen_data <- + Map.take(data, ["album", "artist", "title", "length"]) + |> Map.put("type", "Audio"), + {:ok, activity} <- + ActivityPub.listen(%{ + actor: user, + to: to, + object: listen_data, + context: Utils.generate_context_id(), + additional: %{cc: cc} + }) do + {:ok, activity} + end + end + def post(user, %{"status" => _} = data) do with {:ok, draft} <- Pleroma.Web.CommonAPI.ActivityDraft.create(user, data) do draft.changes diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index f28a66090..0f4a5eb25 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -510,4 +510,43 @@ test "does not allow to vote twice" do assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1]) end end + + describe "listen/2" do + test "returns a valid activity" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.listen(user, %{ + "title" => "lain radio episode 1", + "album" => "lain radio", + "artist" => "lain", + "length" => 180_000 + }) + + object = Object.normalize(activity) + + assert object.data["title"] == "lain radio episode 1" + + assert Visibility.get_visibility(activity) == "public" + end + + test "respects visibility=private" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.listen(user, %{ + "title" => "lain radio episode 1", + "album" => "lain radio", + "artist" => "lain", + "length" => 180_000, + "visibility" => "private" + }) + + object = Object.normalize(activity) + + assert object.data["title"] == "lain radio episode 1" + + assert Visibility.get_visibility(activity) == "private" + end + end end From 7cad6ea67a47df2776a15dd69b9e408c517800e6 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 28 Sep 2019 02:12:12 +0000 Subject: [PATCH 263/272] pleroma api: hook up scrobbler controller --- lib/pleroma/web/activity_pub/activity_pub.ex | 17 +++++ .../web/mastodon_api/views/status_view.ex | 4 ++ .../controllers/pleroma_api_controller.ex | 42 ++++++++++++- lib/pleroma/web/router.ex | 11 ++++ .../controllers/scrobble_controller_test.exs | 63 +++++++++++++++++++ 5 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 test/web/pleroma_api/controllers/scrobble_controller_test.exs diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 425073541..95f994c17 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -608,6 +608,23 @@ defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}, _) do defp restrict_thread_visibility(query, _, _), do: query + def fetch_user_abstract_activities(user, reading_user, params \\ %{}) do + params = + params + |> Map.put("user", reading_user) + |> Map.put("actor_id", user.ap_id) + |> Map.put("whole_db", true) + + recipients = + user_activities_recipients(%{ + "godmode" => params["godmode"], + "reading_user" => reading_user + }) + + fetch_activities(recipients, params) + |> Enum.reverse() + end + def fetch_user_activities(user, reading_user, params \\ %{}) do params = params diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index cf024a83c..d398f7853 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -385,6 +385,10 @@ def render("listen.json", %{activity: %Activity{data: %{"type" => "Listen"}} = a } end + def render("listens.json", opts) do + safe_render_many(opts.activities, StatusView, "listen.json", opts) + end + def render("poll.json", %{object: object} = opts) do {multiple, options} = case object.data do diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index d17ccf84d..1b0ed1f40 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -5,11 +5,13 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do use Pleroma.Web, :controller - import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, fetch_integer_param: 2] alias Pleroma.Conversation.Participation alias Pleroma.Notification + alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.StatusView @@ -86,4 +88,42 @@ def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) d |> render("index.json", %{notifications: notifications, for: user}) end end + + def update_now_playing(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do + params = + if !params["length"] do + params + else + params + |> Map.put("length", fetch_integer_param(params, "length")) + end + + with {:ok, activity} <- CommonAPI.listen(user, params) do + conn + |> put_view(StatusView) + |> render("listen.json", %{activity: activity, for: user}) + else + {:error, message} -> + conn + |> put_status(:bad_request) + |> json(%{"error" => message}) + end + end + + def user_now_playing(%{assigns: %{user: reading_user}} = conn, params) do + with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do + params = Map.put(params, "type", ["Listen"]) + + activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params) + + conn + |> add_link_headers(activities) + |> put_view(StatusView) + |> render("listens.json", %{ + activities: activities, + for: reading_user, + as: :activity + }) + end + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 805bef16f..bd5f02af1 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -300,6 +300,17 @@ defmodule Pleroma.Web.Router do patch("/conversations/:id", PleromaAPIController, :update_conversation) post("/notifications/read", PleromaAPIController, :read_notification) end + + scope [] do + pipe_through(:oauth_write) + post("/now-playing", PleromaAPIController, :update_now_playing) + end + end + + scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do + pipe_through([:api, :oauth_read_or_public]) + + get("/accounts/:id/now-playing", PleromaAPIController, :user_now_playing) end scope "/api/v1", Pleroma.Web.MastodonAPI do diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs new file mode 100644 index 000000000..8cbb5889e --- /dev/null +++ b/test/web/pleroma_api/controllers/scrobble_controller_test.exs @@ -0,0 +1,63 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Web.CommonAPI + import Pleroma.Factory + + describe "POST /api/v1/pleroma/now-playing" do + test "works correctly", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/pleroma/now-playing", %{ + "title" => "lain radio episode 1", + "artist" => "lain", + "album" => "lain radio", + "length" => "180000" + }) + + assert %{"title" => "lain radio episode 1"} = json_response(conn, 200) + end + end + + describe "GET /api/v1/pleroma/accounts/:id/now-playing" do + test "works correctly", %{conn: conn} do + user = insert(:user) + + {:ok, _activity} = + CommonAPI.listen(user, %{ + "title" => "lain radio episode 1", + "artist" => "lain", + "album" => "lain radio" + }) + + {:ok, _activity} = + CommonAPI.listen(user, %{ + "title" => "lain radio episode 2", + "artist" => "lain", + "album" => "lain radio" + }) + + {:ok, _activity} = + CommonAPI.listen(user, %{ + "title" => "lain radio episode 3", + "artist" => "lain", + "album" => "lain radio" + }) + + conn = + conn + |> get("/api/v1/pleroma/accounts/#{user.id}/now-playing") + + result = json_response(conn, 200) + + assert length(result) == 3 + end + end +end From 53506da414f6377b6c7afdb686f3d25e55d29c05 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 28 Sep 2019 02:13:26 +0000 Subject: [PATCH 264/272] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61323970a..80d5e1ac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Refreshing poll results for remote polls - Admin API: Add ability to require password reset +- Mastodon API: Account entities now include `follow_requests_count` (planned Mastodon 3.x addition) +- Pleroma API: `GET /api/v1/pleroma/accounts/:id/now-playing` to get a list of recently scrobbled items +- Pleroma API: `POST /api/v1/pleroma/now-playing` to scrobble a media item ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) From e7309d3b606f4ede3282cf559b30ba23f62cbea5 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 28 Sep 2019 11:57:24 +0000 Subject: [PATCH 265/272] test: transmogrifier: add test proving that transmogrifier can handle outgoing listens --- test/web/activity_pub/transmogrifier_test.exs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 9040c87ca..f77311b3c 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1219,6 +1219,14 @@ test "it strips BCC field" do assert is_nil(modified["bcc"]) end + + test "it can handle Listen activities" do + listen_activity = insert(:listen) + + {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data) + + assert modified["type"] == "Listen" + end end describe "user upgrade" do From 71eff09e564ae3eeaf02acecbb8d89b7d4e2e511 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 28 Sep 2019 12:12:35 +0000 Subject: [PATCH 266/272] common api: make sure the generated IR is actually federatable --- lib/pleroma/web/common_api/common_api.ex | 6 ++++-- test/web/activity_pub/transmogrifier_test.exs | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index a040a6ce2..b02c47059 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -217,14 +217,16 @@ def listen(user, %{"title" => _} = data) do {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil), listen_data <- Map.take(data, ["album", "artist", "title", "length"]) - |> Map.put("type", "Audio"), + |> Map.put("type", "Audio") + |> Map.put("to", to) + |> Map.put("cc", cc), {:ok, activity} <- ActivityPub.listen(%{ actor: user, to: to, object: listen_data, context: Utils.generate_context_id(), - additional: %{cc: cc} + additional: %{"cc" => cc} }) do {:ok, activity} end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index f77311b3c..2c6357fe6 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1226,6 +1226,12 @@ test "it can handle Listen activities" do {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data) assert modified["type"] == "Listen" + + user = insert(:user) + + {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"}) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) end end From 84712c35f9b316b0891edfa791aeb5e358613bd2 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 28 Sep 2019 12:28:39 +0000 Subject: [PATCH 267/272] activitypub: object view: include child object for Listen activities --- lib/pleroma/web/activity_pub/views/object_view.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index 0d63f0707..88c55acdd 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -15,7 +15,8 @@ def render("object.json", %{object: %Object{} = object}) do Map.merge(base, additional) end - def render("object.json", %{object: %Activity{data: %{"type" => "Create"}} = activity}) do + def render("object.json", %{object: %Activity{data: %{"type" => activity_type}} = activity}) + when activity_type in ["Create", "Listen"] do base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header() object = Object.normalize(activity) From 8b34b221cbec366e0a605b9e64dafceb76ed3fd3 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 28 Sep 2019 12:29:00 +0000 Subject: [PATCH 268/272] common api: add some missing IR bits for listen activities' children --- lib/pleroma/web/common_api/common_api.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index b02c47059..2ec017ff8 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -219,7 +219,8 @@ def listen(user, %{"title" => _} = data) do Map.take(data, ["album", "artist", "title", "length"]) |> Map.put("type", "Audio") |> Map.put("to", to) - |> Map.put("cc", cc), + |> Map.put("cc", cc) + |> Map.put("actor", user.ap_id), {:ok, activity} <- ActivityPub.listen(%{ actor: user, From a6e1469767cd716eccf1106e3704130a4fc909b8 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sun, 29 Sep 2019 00:18:06 +0000 Subject: [PATCH 269/272] router: change scrobble timeline route from now-playing to scrobbles --- docs/api/pleroma_api.md | 6 ++++-- .../web/pleroma_api/controllers/pleroma_api_controller.ex | 2 +- lib/pleroma/web/router.ex | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 183cf8a28..33116b4b9 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -440,7 +440,7 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * Response: the archive of the pack with a 200 status code, 403 if the pack is not set as shared, 404 if the pack does not exist -## `GET /api/v1/pleroma/accounts/:uid/now-playing` +## `GET /api/v1/pleroma/accounts/:id/scrobbles` ### Requests a list of current and recent Listen activities for an account * Method `GET` * Authentication: not required @@ -450,11 +450,13 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa ```json [ { + "account": {...}, "id": "1234", "title": "Some Title", "artist": "Some Artist", "album": "Some Album", - "length": 180000 + "length": 180000, + "created_at": "2019-09-28T12:40:45.000Z" } ] ``` diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 1b0ed1f40..6010732db 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -110,7 +110,7 @@ def update_now_playing(%{assigns: %{user: user}} = conn, %{"title" => _} = param end end - def user_now_playing(%{assigns: %{user: reading_user}} = conn, params) do + def user_scrobbles(%{assigns: %{user: reading_user}} = conn, params) do with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do params = Map.put(params, "type", ["Listen"]) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index bd5f02af1..8966e8cc0 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -310,7 +310,7 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do pipe_through([:api, :oauth_read_or_public]) - get("/accounts/:id/now-playing", PleromaAPIController, :user_now_playing) + get("/accounts/:id/scrobbles", PleromaAPIController, :user_scrobbles) end scope "/api/v1", Pleroma.Web.MastodonAPI do From e653edd182338fa8f4396341cea26cd5568f0107 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sun, 29 Sep 2019 00:25:42 +0000 Subject: [PATCH 270/272] split scrobble functions into their own controller --- .../controllers/pleroma_api_controller.ex | 42 +-------------- .../controllers/scrobble_controller.ex | 52 +++++++++++++++++++ lib/pleroma/web/router.ex | 4 +- 3 files changed, 55 insertions(+), 43 deletions(-) create mode 100644 lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 6010732db..d17ccf84d 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -5,13 +5,11 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do use Pleroma.Web, :controller - import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, fetch_integer_param: 2] + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] alias Pleroma.Conversation.Participation alias Pleroma.Notification - alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.StatusView @@ -88,42 +86,4 @@ def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) d |> render("index.json", %{notifications: notifications, for: user}) end end - - def update_now_playing(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do - params = - if !params["length"] do - params - else - params - |> Map.put("length", fetch_integer_param(params, "length")) - end - - with {:ok, activity} <- CommonAPI.listen(user, params) do - conn - |> put_view(StatusView) - |> render("listen.json", %{activity: activity, for: user}) - else - {:error, message} -> - conn - |> put_status(:bad_request) - |> json(%{"error" => message}) - end - end - - def user_scrobbles(%{assigns: %{user: reading_user}} = conn, params) do - with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do - params = Map.put(params, "type", ["Listen"]) - - activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params) - - conn - |> add_link_headers(activities) - |> put_view(StatusView) - |> render("listens.json", %{ - activities: activities, - for: reading_user, - as: :activity - }) - end - end end diff --git a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex new file mode 100644 index 000000000..ac6cd8edd --- /dev/null +++ b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ScrobbleController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, fetch_integer_param: 2] + + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.StatusView + + def update_now_playing(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do + params = + if !params["length"] do + params + else + params + |> Map.put("length", fetch_integer_param(params, "length")) + end + + with {:ok, activity} <- CommonAPI.listen(user, params) do + conn + |> put_view(StatusView) + |> render("listen.json", %{activity: activity, for: user}) + else + {:error, message} -> + conn + |> put_status(:bad_request) + |> json(%{"error" => message}) + end + end + + def user_scrobbles(%{assigns: %{user: reading_user}} = conn, params) do + with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do + params = Map.put(params, "type", ["Listen"]) + + activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params) + + conn + |> add_link_headers(activities) + |> put_view(StatusView) + |> render("listens.json", %{ + activities: activities, + for: reading_user, + as: :activity + }) + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8966e8cc0..8e3a72656 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -303,14 +303,14 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_write) - post("/now-playing", PleromaAPIController, :update_now_playing) + post("/now-playing", ScrobbleController, :update_now_playing) end end scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do pipe_through([:api, :oauth_read_or_public]) - get("/accounts/:id/scrobbles", PleromaAPIController, :user_scrobbles) + get("/accounts/:id/scrobbles", ScrobbleController, :user_scrobbles) end scope "/api/v1", Pleroma.Web.MastodonAPI do From 211008ae2f1ea97490a0ac70b8c801e58af6834c Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sun, 29 Sep 2019 00:35:40 +0000 Subject: [PATCH 271/272] test: fix scrobble controller tests --- test/web/pleroma_api/controllers/scrobble_controller_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs index 8cbb5889e..b86bd2250 100644 --- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs +++ b/test/web/pleroma_api/controllers/scrobble_controller_test.exs @@ -26,7 +26,7 @@ test "works correctly", %{conn: conn} do end end - describe "GET /api/v1/pleroma/accounts/:id/now-playing" do + describe "GET /api/v1/pleroma/accounts/:id/scrobbles" do test "works correctly", %{conn: conn} do user = insert(:user) @@ -53,7 +53,7 @@ test "works correctly", %{conn: conn} do conn = conn - |> get("/api/v1/pleroma/accounts/#{user.id}/now-playing") + |> get("/api/v1/pleroma/accounts/#{user.id}/scrobbles") result = json_response(conn, 200) From 1d7cbdaf7b2f3ff6576959ed26885d7545f31a14 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sun, 29 Sep 2019 02:18:34 +0000 Subject: [PATCH 272/272] change new scrobble endpoint --- CHANGELOG.md | 4 ++-- docs/api/pleroma_api.md | 2 +- .../web/pleroma_api/controllers/scrobble_controller.ex | 2 +- lib/pleroma/web/router.ex | 2 +- test/web/pleroma_api/controllers/scrobble_controller_test.exs | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80d5e1ac9..3d9424c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Refreshing poll results for remote polls - Admin API: Add ability to require password reset - Mastodon API: Account entities now include `follow_requests_count` (planned Mastodon 3.x addition) -- Pleroma API: `GET /api/v1/pleroma/accounts/:id/now-playing` to get a list of recently scrobbled items -- Pleroma API: `POST /api/v1/pleroma/now-playing` to scrobble a media item +- Pleroma API: `GET /api/v1/pleroma/accounts/:id/scrobbles` to get a list of recently scrobbled items +- Pleroma API: `POST /api/v1/pleroma/scrobble` to scrobble a media item ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 33116b4b9..41889a0ef 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -461,7 +461,7 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa ] ``` -## `POST /api/v1/pleroma/now-playing` +## `POST /api/v1/pleroma/scrobble` ### Creates a new Listen activity for an account * Method `POST` * Authentication: required diff --git a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex index ac6cd8edd..0fb978c5d 100644 --- a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleController do alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.StatusView - def update_now_playing(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do + def new_scrobble(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do params = if !params["length"] do params diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8e3a72656..bf32cff1e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -303,7 +303,7 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_write) - post("/now-playing", ScrobbleController, :update_now_playing) + post("/scrobble", ScrobbleController, :new_scrobble) end end diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs index b86bd2250..881f8012c 100644 --- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs +++ b/test/web/pleroma_api/controllers/scrobble_controller_test.exs @@ -8,14 +8,14 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do alias Pleroma.Web.CommonAPI import Pleroma.Factory - describe "POST /api/v1/pleroma/now-playing" do + describe "POST /api/v1/pleroma/scrobble" do test "works correctly", %{conn: conn} do user = insert(:user) conn = conn |> assign(:user, user) - |> post("/api/v1/pleroma/now-playing", %{ + |> post("/api/v1/pleroma/scrobble", %{ "title" => "lain radio episode 1", "artist" => "lain", "album" => "lain radio",

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