From 385356aad0dd7eac0695bb1597ba1e52b5f17b40 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 24 Dec 2019 20:45:46 +0300 Subject: [PATCH 01/26] fix oauth scopes for AdminApi#reports_update --- .../web/admin_api/admin_api_controller.ex | 2 +- .../admin_api/admin_api_controller_test.exs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 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 c8abeff06..ddae139c6 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -66,7 +66,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, %{scopes: ["write:reports"], admin: true} - when action in [:report_update_state, :report_respond] + when action in [:reports_update] ) plug( diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 49ff005b6..4156ef50d 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1418,6 +1418,30 @@ test "returns 404 when report id is invalid", %{conn: conn} do } end + test "requires write:reports scope", %{conn: conn, id: id, admin: admin} do + read_token = insert(:oauth_token, user: admin, scopes: ["read"]) + write_token = insert(:oauth_token, user: admin, scopes: ["write:reports"]) + + response = + conn + |> assign(:token, read_token) + |> patch("/api/pleroma/admin/reports", %{ + "reports" => [%{"state" => "resolved", "id" => id}] + }) + |> json_response(403) + + assert response == %{ + "error" => "Insufficient permissions: admin:write:reports | write:reports." + } + + conn + |> assign(:token, write_token) + |> patch("/api/pleroma/admin/reports", %{ + "reports" => [%{"state" => "resolved", "id" => id}] + }) + |> json_response(:no_content) + end + test "mark report as resolved", %{conn: conn, id: id, admin: admin} do conn |> patch("/api/pleroma/admin/reports", %{ From 2ee6754095f5b81807efe97c73ada42e2c990ede Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 14 Jan 2020 17:24:26 +0100 Subject: [PATCH 02/26] Mix Tasks: Add pleroma.benchmarks.tags --- benchmarks/load_testing/generator.ex | 44 +++++++++++++- lib/mix/tasks/pleroma/benchmarks/tags.ex | 57 +++++++++++++++++++ .../controllers/timeline_controller.ex | 14 +++-- 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 lib/mix/tasks/pleroma/benchmarks/tags.ex diff --git a/benchmarks/load_testing/generator.ex b/benchmarks/load_testing/generator.ex index a957e0ffb..3f88fefd7 100644 --- a/benchmarks/load_testing/generator.ex +++ b/benchmarks/load_testing/generator.ex @@ -9,7 +9,7 @@ def generate_like_activities(user, posts) do {time, _} = :timer.tc(fn -> Task.async_stream( - Enum.take_random(posts, count_likes), + Enum.take_random(posts, count_likes), fn post -> {:ok, _, _} = CommonAPI.favorite(post.id, user) end, max_concurrency: 10, timeout: 30_000 @@ -142,6 +142,48 @@ defp do_generate_activity(users) do CommonAPI.post(Enum.random(users), post) end + def generate_power_intervals(opts \\ []) do + count = Keyword.get(opts, :count, 20) + power = Keyword.get(opts, :power, 2) + IO.puts("Generating #{count} intervals for a power #{power} series...") + counts = Enum.map(1..count, fn n -> :math.pow(n, power) end) + sum = Enum.sum(counts) + + densities = + Enum.map(counts, fn c -> + c / sum + end) + + densities + |> Enum.reduce(0, fn density, acc -> + if acc == 0 do + [{0, density}] + else + [{_, lower} | _] = acc + [{lower, lower + density} | acc] + end + end) + |> Enum.reverse() + end + + def generate_tagged_activities(opts \\ []) do + tag_count = Keyword.get(opts, :tag_count, 20) + users = Keyword.get(opts, :users, Repo.all(User)) + activity_count = Keyword.get(opts, :count, 200_000) + + intervals = generate_power_intervals(count: tag_count) + + IO.puts( + "Generating #{activity_count} activities using #{tag_count} different tags of format `tag_n`, starting at tag_0" + ) + + Enum.each(1..activity_count, fn _ -> + random = :rand.uniform() + i = Enum.find_index(intervals, fn {lower, upper} -> lower <= random && upper > random end) + CommonAPI.post(Enum.random(users), %{"status" => "a post with the tag #tag_#{i}"}) + end) + end + defp do_generate_activity_with_mention(user, users) do mentions_cnt = Enum.random([2, 3, 4, 5]) with_user = Enum.random([true, false]) diff --git a/lib/mix/tasks/pleroma/benchmarks/tags.ex b/lib/mix/tasks/pleroma/benchmarks/tags.ex new file mode 100644 index 000000000..73796b5f9 --- /dev/null +++ b/lib/mix/tasks/pleroma/benchmarks/tags.ex @@ -0,0 +1,57 @@ +defmodule Mix.Tasks.Pleroma.Benchmarks.Tags do + use Mix.Task + alias Pleroma.Repo + alias Pleroma.LoadTesting.Generator + import Ecto.Query + + def run(_args) do + Mix.Pleroma.start_pleroma() + activities_count = Repo.aggregate(from(a in Pleroma.Activity), :count, :id) + + if activities_count == 0 do + IO.puts("Did not find any activities, cleaning and generating") + clean_tables() + Generator.generate_users(users_max: 10) + Generator.generate_tagged_activities() + else + IO.puts("Found #{activities_count} activities, won't generate new ones") + end + + tags = Enum.map(0..20, fn i -> {"For #tag_#{i}", "tag_#{i}"} end) + + Enum.each(tags, fn {_, tag} -> + query = + from(o in Pleroma.Object, + where: fragment("(?)->'tag' \\? (?)", o.data, ^tag) + ) + + count = Repo.aggregate(query, :count, :id) + IO.puts("Database contains #{count} posts tagged with #{tag}") + end) + + user = Repo.all(Pleroma.User) |> List.first() + + Benchee.run( + %{ + "Hashtag fetching" => fn tag -> + Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching( + %{ + "tag" => tag + }, + user, + false + ) + end + }, + inputs: tags, + time: 5 + ) + end + + defp clean_tables do + IO.puts("Deleting old data...\n") + Ecto.Adapters.SQL.query!(Repo, "TRUNCATE users CASCADE;") + Ecto.Adapters.SQL.query!(Repo, "TRUNCATE activities CASCADE;") + Ecto.Adapters.SQL.query!(Repo, "TRUNCATE objects CASCADE;") + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 384159336..29964a1d4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -77,10 +77,7 @@ def public(%{assigns: %{user: user}} = conn, params) do |> 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"]) - + def hashtag_fetching(params, user, local_only) do tags = [params["tag"], params["any"]] |> List.flatten() @@ -98,7 +95,7 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do |> Map.get("none", []) |> Enum.map(&String.downcase(&1)) - activities = + _activities = params |> Map.put("type", "Create") |> Map.put("local_only", local_only) @@ -109,6 +106,13 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do |> Map.put("tag_all", tag_all) |> Map.put("tag_reject", tag_reject) |> ActivityPub.fetch_public_activities() + end + + # GET /api/v1/timelines/tag/:tag + def hashtag(%{assigns: %{user: user}} = conn, params) do + local_only = truthy_param?(params["local"]) + + activities = hashtag_fetching(params, user, local_only) conn |> add_link_headers(activities, %{"local" => local_only}) From 0709757e47a546225163482474a46e8bc3d09837 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 14 Jan 2020 19:53:28 +0300 Subject: [PATCH 03/26] Check if object->data is array when looking up attachment objects to delete --- lib/pleroma/object.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 2452a7389..6c56a9c62 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -203,7 +203,8 @@ defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" from(o in Object, where: fragment( - "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href'))::jsonb \\?| (?)", + "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)", + o.data, o.data, ^hrefs ) From 167e9c45eccf5ddb89077c979b1d587318f78cc0 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 15 Jan 2020 12:37:50 +0100 Subject: [PATCH 04/26] Benchmarks: Move to correct folder --- {lib => benchmarks}/mix/tasks/pleroma/benchmarks/tags.ex | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {lib => benchmarks}/mix/tasks/pleroma/benchmarks/tags.ex (100%) diff --git a/lib/mix/tasks/pleroma/benchmarks/tags.ex b/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex similarity index 100% rename from lib/mix/tasks/pleroma/benchmarks/tags.ex rename to benchmarks/mix/tasks/pleroma/benchmarks/tags.ex From 81133702d4246e5e5c17ea4d4119747dc880edd6 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 17 Jan 2020 20:20:37 +0300 Subject: [PATCH 05/26] Delete attachments after object and cache cleanup --- lib/pleroma/object.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 6c56a9c62..499339982 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -180,10 +180,10 @@ def swap_object_with_tombstone(object) do def delete(%Object{data: %{"id" => id}} = object) do with {:ok, _obj} = swap_object_with_tombstone(object), - :ok <- delete_attachments(object), deleted_activity = Activity.delete_all_by_object_ap_id(id), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), - {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do + {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path), + :ok <- delete_attachments(object) do {:ok, object, deleted_activity} end end From 6cf3b19a38d08b37a686cd1059604816d11708f1 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 19 Jan 2020 07:02:16 +0100 Subject: [PATCH 06/26] transmogrifier.ex: simplify handle_incoming of actors --- lib/pleroma/web/activity_pub/transmogrifier.ex | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 3fa789d53..2b8bfc3bd 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -658,24 +658,8 @@ def handle_incoming( with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) - locked = new_user_data[:locked] || false - attachment = get_in(new_user_data, [:source_data, "attachment"]) || [] - invisible = new_user_data[:invisible] || false - - fields = - attachment - |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) - |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) - - update_data = - new_user_data - |> Map.take([:avatar, :banner, :bio, :name, :also_known_as]) - |> Map.put(:fields, fields) - |> Map.put(:locked, locked) - |> Map.put(:invisible, invisible) - actor - |> User.upgrade_changeset(update_data, true) + |> User.upgrade_changeset(new_user_data, true) |> User.update_and_set_cache() ActivityPub.update(%{ From 205e73058d076385e234dafe011a7cd3fad68ef8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 19 Jan 2020 13:33:46 +0300 Subject: [PATCH 07/26] mix.lock: update mock to 0.3.4 This version adds Mock.passthrough/1 which I need to use in a test --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index ff22791a4..2b449329c 100644 --- a/mix.lock +++ b/mix.lock @@ -63,7 +63,7 @@ "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, - "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, + "mock": {:hex, :mock, "0.3.4", "c5862eb3b8c64237f45f586cf00c9d892ba07bb48305a43319d428ce3c2897dd", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"}, "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]}, From d6a532bf0f280cc191a9f2c1f53af31c451481d9 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 19 Jan 2020 19:45:20 +0300 Subject: [PATCH 08/26] Delete attachments asynchronously --- lib/pleroma/object.ex | 79 ++--------------- .../workers/attachments_cleanup_worker.ex | 87 +++++++++++++++++++ test/object_test.exs | 6 ++ 3 files changed, 99 insertions(+), 73 deletions(-) create mode 100644 lib/pleroma/workers/attachments_cleanup_worker.ex diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 499339982..38e372f6d 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -19,6 +19,8 @@ defmodule Pleroma.Object do @type t() :: %__MODULE__{} + @derive {Jason.Encoder, only: [:data]} + schema "objects" do field(:data, :map) @@ -183,83 +185,14 @@ def delete(%Object{data: %{"id" => id}} = object) do deleted_activity = Activity.delete_all_by_object_ap_id(id), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path), - :ok <- delete_attachments(object) do + {:ok, _} <- + Pleroma.Workers.AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{ + "object" => object + }) do {:ok, object, deleted_activity} end end - defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" => actor}}) do - hrefs = - Enum.flat_map(attachments, fn attachment -> - Enum.map(attachment["url"], & &1["href"]) - end) - - names = Enum.map(attachments, & &1["name"]) - - uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) - - # find all objects for copies of the attachments, name and actor doesn't matter here - delete_ids = - from(o in Object, - where: - fragment( - "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)", - o.data, - o.data, - ^hrefs - ) - ) - |> Repo.all() - # we should delete 1 object for any given attachment, but don't delete files if - # there are more than 1 object for it - |> Enum.reduce(%{}, fn %{ - id: id, - data: %{ - "url" => [%{"href" => href}], - "actor" => obj_actor, - "name" => name - } - }, - acc -> - Map.update(acc, href, %{id: id, count: 1}, fn val -> - case obj_actor == actor and name in names do - true -> - # set id of the actor's object that will be deleted - %{val | id: id, count: val.count + 1} - - false -> - # another actor's object, just increase count to not delete file - %{val | count: val.count + 1} - end - end) - end) - |> Enum.map(fn {href, %{id: id, count: count}} -> - # only delete files that have single instance - with 1 <- count do - prefix = - case Pleroma.Config.get([Pleroma.Upload, :base_url]) do - nil -> "media" - _ -> "" - end - - base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url()) - - file_path = String.trim_leading(href, "#{base_url}/#{prefix}") - - uploader.delete_file(file_path) - end - - id - end) - - from(o in Object, where: o.id in ^delete_ids) - |> Repo.delete_all() - - :ok - end - - defp delete_attachments(%{data: _data}), do: :ok - def prune(%Object{data: %{"id" => id}} = object) do with {:ok, object} <- Repo.delete(object), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex new file mode 100644 index 000000000..f8239ece6 --- /dev/null +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -0,0 +1,87 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.AttachmentsCleanupWorker do + import Ecto.Query + + alias Pleroma.Object + alias Pleroma.Repo + + use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup" + + @impl Oban.Worker + def perform( + %{"object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}}}, + _job + ) do + hrefs = + Enum.flat_map(attachments, fn attachment -> + Enum.map(attachment["url"], & &1["href"]) + end) + + names = Enum.map(attachments, & &1["name"]) + + uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) + + # find all objects for copies of the attachments, name and actor doesn't matter here + delete_ids = + from(o in Object, + where: + fragment( + "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)", + o.data, + o.data, + ^hrefs + ) + ) + # The query above can be time consumptive on large instances until we refactor how uploads are stored + |> Repo.all(timout: :infinity) + # we should delete 1 object for any given attachment, but don't delete files if + # there are more than 1 object for it + |> Enum.reduce(%{}, fn %{ + id: id, + data: %{ + "url" => [%{"href" => href}], + "actor" => obj_actor, + "name" => name + } + }, + acc -> + Map.update(acc, href, %{id: id, count: 1}, fn val -> + case obj_actor == actor and name in names do + true -> + # set id of the actor's object that will be deleted + %{val | id: id, count: val.count + 1} + + false -> + # another actor's object, just increase count to not delete file + %{val | count: val.count + 1} + end + end) + end) + |> Enum.map(fn {href, %{id: id, count: count}} -> + # only delete files that have single instance + with 1 <- count do + prefix = + case Pleroma.Config.get([Pleroma.Upload, :base_url]) do + nil -> "media" + _ -> "" + end + + base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url()) + + file_path = String.trim_leading(href, "#{base_url}/#{prefix}") + + uploader.delete_file(file_path) + end + + id + end) + + from(o in Object, where: o.id in ^delete_ids) + |> Repo.delete_all() + end + + def perform(%{"object" => _object}, _job), do: :ok +end diff --git a/test/object_test.exs b/test/object_test.exs index b002c2bae..997ec9691 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -4,12 +4,14 @@ defmodule Pleroma.ObjectTest do use Pleroma.DataCase + use Oban.Testing, repo: Pleroma.Repo import ExUnit.CaptureLog import Pleroma.Factory import Tesla.Mock alias Pleroma.Activity alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.CommonAPI setup do @@ -99,6 +101,8 @@ test "in subdirectories" do Object.delete(note) + ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker)) + assert Object.get_by_id(attachment.id) == nil assert {:ok, []} == File.ls("#{uploads_dir}/#{path}") @@ -133,6 +137,8 @@ test "with dedupe enabled" do Object.delete(note) + ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker)) + assert Object.get_by_id(attachment.id) == nil assert {:ok, files} = File.ls(uploads_dir) refute filename in files From 0f1fc382d09ef7c364f3d19ef25b98d397b2eba4 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 19 Jan 2020 22:04:14 +0300 Subject: [PATCH 09/26] Add test case for attachment deletion when non-map data.url present in DB --- test/object_test.exs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/object_test.exs b/test/object_test.exs index 997ec9691..9b4e6f0bf 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -143,6 +143,40 @@ test "with dedupe enabled" do assert {:ok, files} = File.ls(uploads_dir) refute filename in files end + + test "with objects that have legacy data.url attribute" do + Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + user = insert(:user) + + {:ok, %Object{} = attachment} = + Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id) + + {:ok, %Object{}} = Object.create(%{url: "https://google.com", actor: user.ap_id}) + + %{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} = + note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}}) + + uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads]) + + path = href |> Path.dirname() |> Path.basename() + + assert {:ok, ["an_image.jpg"]} == File.ls("#{uploads_dir}/#{path}") + + Object.delete(note) + + ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker)) + + assert Object.get_by_id(attachment.id) == nil + + assert {:ok, []} == File.ls("#{uploads_dir}/#{path}") + end end describe "normalizer" do From cde828ff7df64740f36b2fc9dfdbfc8d76a8a78d Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 19 Jan 2020 22:09:47 +0300 Subject: [PATCH 10/26] Fix credo warning --- lib/pleroma/workers/attachments_cleanup_worker.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index f8239ece6..3f421db40 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -35,10 +35,11 @@ def perform( ^hrefs ) ) - # The query above can be time consumptive on large instances until we refactor how uploads are stored + # The query above can be time consumptive on large instances until we + # refactor how uploads are stored |> Repo.all(timout: :infinity) - # we should delete 1 object for any given attachment, but don't delete files if - # there are more than 1 object for it + # we should delete 1 object for any given attachment, but don't delete + # files if there are more than 1 object for it |> Enum.reduce(%{}, fn %{ id: id, data: %{ From dc0498ab2b7cee930f426e37ed4f167c2dc83262 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 16 Jan 2020 19:01:31 +0300 Subject: [PATCH 11/26] Check for unapplied migrations on startup Closes #1328 --- CHANGELOG.md | 1 + lib/pleroma/application.ex | 1 + lib/pleroma/repo.ex | 35 +++++++++++++++++++++++++++++++ test/repo_test.exs | 43 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 182f5e579..af497dcba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - **Breaking**: MDII uploader ### Changed +- **Breaking:** Pleroma won't start if it detects unapplied migrations - **Breaking:** attachments are removed along with statuses when there are no other references to it - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) - **Breaking:** attachment links (`config :pleroma, :instance, no_attachment_links` and `config :pleroma, Pleroma.Upload, link_name`) disabled by default diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 2ae052069..e17068876 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -33,6 +33,7 @@ def user_agent do def start(_type, _args) do Pleroma.HTML.compile_scrubbers() Pleroma.Config.DeprecationWarnings.warn() + Pleroma.Repo.check_migrations_applied!() setup_instrumenters() load_custom_modules() diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex index f57e088bc..cb0b6653c 100644 --- a/lib/pleroma/repo.ex +++ b/lib/pleroma/repo.ex @@ -8,6 +8,8 @@ defmodule Pleroma.Repo do adapter: Ecto.Adapters.Postgres, migration_timestamps: [type: :naive_datetime_usec] + require Logger + defmodule Instrumenter do use Prometheus.EctoInstrumenter end @@ -47,4 +49,37 @@ def get_assoc(resource, association) do _ -> {:error, :not_found} end end + + def check_migrations_applied!() do + unless Pleroma.Config.get( + [:i_am_aware_this_may_cause_data_loss, :disable_migration_check], + false + ) do + Ecto.Migrator.with_repo(__MODULE__, fn repo -> + down_migrations = + Ecto.Migrator.migrations(repo) + |> Enum.reject(fn + {:up, _, _} -> true + {:down, _, _} -> false + end) + + if length(down_migrations) > 0 do + down_migrations_text = + Enum.map(down_migrations, fn {:down, id, name} -> "- #{name} (#{id})\n" end) + + Logger.error( + "The following migrations were not applied:\n#{down_migrations_text}If you want to start Pleroma anyway, set\nconfig :pleroma, :i_am_aware_this_may_cause_data_loss, disable_migration_check: true" + ) + + raise Pleroma.Repo.UnappliedMigrationsError + end + end) + else + :ok + end + end +end + +defmodule Pleroma.Repo.UnappliedMigrationsError do + defexception message: "Unapplied Migrations detected" end diff --git a/test/repo_test.exs b/test/repo_test.exs index 85b64d4d1..5526b0327 100644 --- a/test/repo_test.exs +++ b/test/repo_test.exs @@ -4,7 +4,10 @@ defmodule Pleroma.RepoTest do use Pleroma.DataCase + import ExUnit.CaptureLog import Pleroma.Factory + import Mock + alias Pleroma.User describe "find_resource/1" do @@ -46,4 +49,44 @@ test "return error if has not assoc " do assert Repo.get_assoc(token, :user) == {:error, :not_found} end end + + describe "check_migrations_applied!" do + setup_with_mocks([ + {Ecto.Migrator, [], + [ + with_repo: fn repo, fun -> passthrough([repo, fun]) end, + migrations: fn Pleroma.Repo -> + [ + {:up, 20_191_128_153_944, "fix_missing_following_count"}, + {:up, 20_191_203_043_610, "create_report_notes"}, + {:down, 20_191_220_174_645, "add_scopes_to_pleroma_feo_auth_records"} + ] + end + ]} + ]) do + :ok + end + + test "raises if it detects unapplied migrations" do + assert_raise Pleroma.Repo.UnappliedMigrationsError, fn -> + capture_log(&Repo.check_migrations_applied!/0) + end + end + + test "doesn't do anything if disabled" do + disable_migration_check = + Pleroma.Config.get([:i_am_aware_this_may_cause_data_loss, :disable_migration_check]) + + Pleroma.Config.put([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true) + + on_exit(fn -> + Pleroma.Config.put( + [:i_am_aware_this_may_cause_data_loss, :disable_migration_check], + disable_migration_check + ) + end) + + assert :ok == Repo.check_migrations_applied!() + end + end end From 5c533e10e73d92b753d9ac20b2d7ab14f42649b2 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 20 Jan 2020 11:53:14 +0100 Subject: [PATCH 12/26] Bump credo to 1.1.5 --- lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex | 2 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- .../mastodon_api/controllers/subscription_controller.ex | 2 +- lib/pleroma/web/oauth/oauth_controller.ex | 2 +- mix.exs | 2 +- mix.lock | 2 +- test/notification_test.exs | 4 ++-- .../activity_pub/transmogrifier/follow_handling_test.exs | 2 +- test/web/admin_api/admin_api_controller_test.exs | 2 +- test/web/common_api/common_api_utils_test.exs | 8 ++++---- test/web/twitter_api/password_controller_test.exs | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex index 4eaea00d8..c184c3b66 100644 --- a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -20,7 +20,7 @@ def filter(%{"type" => message_type} = message) do with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]), rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]), true <- - length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type), + Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type), false <- length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type), {:ok, _} <- filter(message["object"]) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 529169c1b..78b77a97a 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -639,7 +639,7 @@ def get_password_reset(conn, %{"nickname" => nickname}) do def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) - Enum.map(users, &User.force_password_reset_async/1) + Enum.each(users, &User.force_password_reset_async/1) ModerationLog.insert_log(%{ actor: admin, diff --git a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex index fc7d52824..11f7b85d3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex @@ -6,9 +6,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do @moduledoc "The module represents functions to manage user subscriptions." use Pleroma.Web, :controller + alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View alias Pleroma.Web.Push alias Pleroma.Web.Push.Subscription - alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View action_fallback(:errors) diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index d31a3d91c..5292aedf2 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -14,10 +14,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do alias Pleroma.Web.ControllerHelper alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization + alias Pleroma.Web.OAuth.Scopes alias Pleroma.Web.OAuth.Token alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken - alias Pleroma.Web.OAuth.Scopes require Logger diff --git a/mix.exs b/mix.exs index c2e0b940f..0aa7c862f 100644 --- a/mix.exs +++ b/mix.exs @@ -124,7 +124,7 @@ defp deps do {:earmark, "~> 1.3"}, {:bbcode, "~> 0.1.1"}, {:ex_machina, "~> 2.3", only: :test}, - {:credo, "~> 0.9.3", only: [:dev, :test]}, + {:credo, "~> 1.1.0", only: [:dev, :test], runtime: false}, {:mock, "~> 0.3.3", only: :test}, {:crypt, git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"}, diff --git a/mix.lock b/mix.lock index ff22791a4..9bf7804b3 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm"}, - "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"}, + "credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [: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"}, diff --git a/test/notification_test.exs b/test/notification_test.exs index f5f23bb5a..9a1c2f2b5 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -745,7 +745,7 @@ test "it doesn't return notifications from a blocked user when with_muted is set {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"}) - assert length(Notification.for_user(user, %{with_muted: true})) == 0 + assert Enum.empty?(Notification.for_user(user, %{with_muted: true})) end test "it doesn't return notifications from a domain-blocked user when with_muted is set" do @@ -755,7 +755,7 @@ test "it doesn't return notifications from a domain-blocked user when with_muted {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"}) - assert length(Notification.for_user(user, %{with_muted: true})) == 0 + assert Enum.empty?(Notification.for_user(user, %{with_muted: true})) end test "it returns notifications from muted threads when with_muted is set" do diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs index 7d6d0814d..1c88b05c2 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -78,7 +78,7 @@ test "with locked accounts, it does not create a follow or an accept" do ) |> Repo.all() - assert length(accepts) == 0 + assert Enum.empty?(accepts) end test "it works for follow requests when you are already followed, creating a new accept activity" do diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index a3fbb6041..d70fe54b2 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -2840,7 +2840,7 @@ test "GET /instances/:instance/statuses", %{conn: conn} do response = json_response(ret_conn, 200) - assert length(response) == 0 + assert Enum.empty?(response) end end diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index 2588898d0..4b761e039 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -307,7 +307,7 @@ test "for private posts, not a reply" do {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private", nil) assert length(to) == 2 - assert length(cc) == 0 + assert Enum.empty?(cc) assert mentioned_user.ap_id in to assert user.follower_address in to @@ -323,7 +323,7 @@ test "for private posts, a reply" do {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil) assert length(to) == 3 - assert length(cc) == 0 + assert Enum.empty?(cc) assert mentioned_user.ap_id in to assert third_user.ap_id in to @@ -338,7 +338,7 @@ test "for direct posts, not a reply" do {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct", nil) assert length(to) == 1 - assert length(cc) == 0 + assert Enum.empty?(cc) assert mentioned_user.ap_id in to end @@ -353,7 +353,7 @@ test "for direct posts, a reply" do {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil) assert length(to) == 2 - assert length(cc) == 0 + assert Enum.empty?(cc) assert mentioned_user.ap_id in to assert third_user.ap_id in to diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs index 840c84a05..29ba7d265 100644 --- a/test/web/twitter_api/password_controller_test.exs +++ b/test/web/twitter_api/password_controller_test.exs @@ -55,7 +55,7 @@ test "it returns HTTP 200", %{conn: conn} do user = refresh_record(user) assert Comeonin.Pbkdf2.checkpw("test", user.password_hash) - assert length(Token.get_user_tokens(user)) == 0 + assert Enum.empty?(Token.get_user_tokens(user)) end test "it sets password_reset_pending to false", %{conn: conn} do From 271afcd940b743b84fae2ee40245d1e0c53cc714 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 12:19:15 +0100 Subject: [PATCH 13/26] Add benchmark of any/all tag options --- .../mix/tasks/pleroma/benchmarks/tags.ex | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex b/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex index 73796b5f9..fd1506907 100644 --- a/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex +++ b/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex @@ -31,6 +31,36 @@ def run(_args) do user = Repo.all(Pleroma.User) |> List.first() + Benchee.run( + %{ + "Hashtag fetching, any" => fn tags -> + Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching( + %{ + "any" => tags + }, + user, + false + ) + end, + # Will always return zero results because no overlapping hashtags are generated. + "Hashtag fetching, all" => fn tags -> + Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching( + %{ + "all" => tags + }, + user, + false + ) + end + }, + inputs: + tags + |> Enum.map(fn {_, v} -> v end) + |> Enum.chunk_every(2) + |> Enum.map(fn tags -> {"For #{inspect(tags)}", tags} end), + time: 5 + ) + Benchee.run( %{ "Hashtag fetching" => fn tag -> From 5fddf988ea45382d8e2307f11205afcc4b468d45 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 13:05:35 +0100 Subject: [PATCH 14/26] Pleroma API: `emoji_reactions_by` does not need authorization --- .../web/pleroma_api/controllers/pleroma_api_controller.ex | 2 +- .../pleroma_api/controllers/pleroma_api_controller_test.exs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) 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 772c535a4..3285dc11b 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -23,7 +23,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do plug( OAuthScopesPlug, %{scopes: ["read:statuses"]} - when action in [:conversation, :conversation_statuses, :emoji_reactions_by] + when action in [:conversation, :conversation_statuses] ) plug( diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs index 3f7ef13bc..fb7500134 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -57,11 +57,6 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) - conn = - conn - |> assign(:user, user) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:statuses"])) - result = conn |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") From 510776ba31f0bb01217fd6585848657f5bceb5f7 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 14:27:59 +0100 Subject: [PATCH 15/26] CommonAPI: Don't error out on double favs/repeats --- lib/pleroma/web/common_api/common_api.ex | 16 ++++++++++++---- test/web/common_api/common_api_test.exs | 12 ++++++------ .../controllers/status_controller_test.exs | 7 +++++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 2f3bcfc3c..c05a6c544 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -85,9 +85,13 @@ def delete(activity_id, user) do def repeat(id_or_ap_id, user, params \\ %{}) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), object <- Object.normalize(activity), - nil <- Utils.get_existing_announce(user.ap_id, object), + announce_activity <- Utils.get_existing_announce(user.ap_id, object), public <- public_announce?(object, params) do - ActivityPub.announce(user, object, nil, true, public) + if announce_activity do + {:ok, announce_activity, object} + else + ActivityPub.announce(user, object, nil, true, public) + end else _ -> {:error, dgettext("errors", "Could not repeat")} end @@ -105,8 +109,12 @@ def unrepeat(id_or_ap_id, user) do def favorite(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), object <- Object.normalize(activity), - nil <- Utils.get_existing_like(user.ap_id, object) do - ActivityPub.like(user, object) + like_activity <- Utils.get_existing_like(user.ap_id, object) do + if like_activity do + {:ok, like_activity, object} + else + ActivityPub.like(user, object) + end else _ -> {:error, dgettext("errors", "Could not favorite")} end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index b5d6d4055..f8963e42e 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -284,22 +284,22 @@ test "favoriting a status" do {:ok, %Activity{}, _} = CommonAPI.favorite(activity.id, user) end - test "retweeting a status twice returns an error" do + test "retweeting a status twice returns the status" do user = insert(:user) other_user = insert(:user) {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"}) - {:ok, %Activity{}, _object} = CommonAPI.repeat(activity.id, user) - {:error, _} = CommonAPI.repeat(activity.id, user) + {:ok, %Activity{} = activity, object} = CommonAPI.repeat(activity.id, user) + {:ok, ^activity, ^object} = CommonAPI.repeat(activity.id, user) end - test "favoriting a status twice returns an error" do + test "favoriting a status twice returns the status" do user = insert(:user) other_user = insert(:user) {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"}) - {:ok, %Activity{}, _object} = CommonAPI.favorite(activity.id, user) - {:error, _} = CommonAPI.favorite(activity.id, user) + {:ok, %Activity{} = activity, object} = CommonAPI.favorite(activity.id, user) + {:ok, ^activity, ^object} = CommonAPI.favorite(activity.id, user) 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 307221c5d..0b75fcc91 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -638,6 +638,13 @@ test "favs a status and returns it", %{conn: conn} do assert to_string(activity.id) == id end + test "favoriting twice will just return 200", %{conn: conn} do + activity = insert(:note_activity) + + post(conn, "/api/v1/statuses/#{activity.id}/favourite") + assert post(conn, "/api/v2/statuses/#{activity.id}/favourite") |> json_response(200) + end + test "returns 400 error for a wrong id", %{conn: conn} do conn = post(conn, "/api/v1/statuses/1/favourite") From 2199d63ddcbbfabb4d0daa70cbebfeac2d50717b Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 15:31:14 +0100 Subject: [PATCH 16/26] StatusControllerTest: Fix typo --- test/web/mastodon_api/controllers/status_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index 0b75fcc91..b03b4b344 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -642,7 +642,7 @@ test "favoriting twice will just return 200", %{conn: conn} do activity = insert(:note_activity) post(conn, "/api/v1/statuses/#{activity.id}/favourite") - assert post(conn, "/api/v2/statuses/#{activity.id}/favourite") |> json_response(200) + assert post(conn, "/api/v1/statuses/#{activity.id}/favourite") |> json_response(200) end test "returns 400 error for a wrong id", %{conn: conn} do From 4c5b5f14dcec51cba8e86bcfcf2943ee9b49b0e4 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 16:24:20 +0100 Subject: [PATCH 17/26] StatusView: Add `emoji_reactions` --- CHANGELOG.md | 1 + docs/API/differences_in_mastoapi_responses.md | 1 + .../web/mastodon_api/views/status_view.ex | 13 ++++++++++++- .../mastodon_api/views/status_view_test.exs | 19 ++++++++++++++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af497dcba..871b01ca3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Captcha: Support native provider - Captcha: Enable by default - Mastodon API: Add support for `account_id` param to filter notifications by the account +- Mastodon API: Add `emoji_reactions` property to Statuses ### Fixed diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md index bb62ed5f2..50076cf98 100644 --- a/docs/API/differences_in_mastoapi_responses.md +++ b/docs/API/differences_in_mastoapi_responses.md @@ -29,6 +29,7 @@ Has these additional fields under the `pleroma` object: - `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` - `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire - `thread_muted`: true if the thread the post belongs to is muted +- `emoji_reactions`: An object with all the emoji reactions with count. Contains no information about the reacting users, for that use the `emoji_reactions_by` endpoint. ## Attachments diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index e9590224b..b59ac39bc 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -253,6 +253,16 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} nil end + emoji_reactions = + with %{data: %{"reactions" => emoji_reactions}} <- object do + Enum.map(emoji_reactions, fn {emoji, users} -> + {emoji, length(users)} + end) + |> Enum.into(%{}) + else + _ -> %{} + end + %{ id: to_string(activity.id), uri: object.data["id"], @@ -293,7 +303,8 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} spoiler_text: %{"text/plain" => summary_plaintext}, expires_at: expires_at, direct_conversation_id: direct_conversation_id, - thread_muted: thread_muted? + thread_muted: thread_muted?, + emoji_reactions: emoji_reactions } } end diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index 17b6ebcbc..b54b19c0b 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -24,6 +24,22 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do :ok end + test "has an emoji reaction list" do + user = insert(:user) + other_user = insert(:user) + third_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => "dae cofe??"}) + + {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, user, "☕") + {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵") + activity = Repo.get(Activity, activity.id) + status = StatusView.render("show.json", activity: activity) + + assert status[:pleroma][:emoji_reactions]["🍵"] == 1 + assert status[:pleroma][:emoji_reactions]["☕"] == 2 + end + test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do user = insert(:user) @@ -172,7 +188,8 @@ test "a note activity" do spoiler_text: %{"text/plain" => HTML.strip_tags(object_data["summary"])}, expires_at: nil, direct_conversation_id: nil, - thread_muted: false + thread_muted: false, + emoji_reactions: %{} } } From 7518f3877f9fb7c62c05292246e4ba82927cb09a Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 20 Jan 2020 16:31:12 +0100 Subject: [PATCH 18/26] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af497dcba..6e6b1609e 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/). - Mastodon API, streaming: Add `pleroma.direct_conversation_id` to the `conversation` stream event payload. - Admin API: Render whole status in grouped reports - Mastodon API: User timelines will now respect blocks, unless you are getting the user timeline of somebody you blocked (which would be empty otherwise). +- Mastodon API: Favoriting / Repeating a post multiple times will now return the identical response every time. Before, executing that action twice would return an error ("already favorited") on the second try. ### Added From ca3b4de2c9ed2c34d2d789e4b5e2c721c0d99f71 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 20 Jan 2020 20:04:25 +0300 Subject: [PATCH 19/26] [#1521] AdminApiControllerTest: fixed create report test (OAuth). --- test/web/admin_api/admin_api_controller_test.exs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index d11b26207..c8f8ba310 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1363,9 +1363,9 @@ test "returns 404 when report id is invalid", %{conn: conn} do } end - test "requires write:reports scope", %{conn: conn, id: id, admin: admin} do - read_token = insert(:oauth_token, user: admin, scopes: ["read"]) - write_token = insert(:oauth_token, user: admin, scopes: ["write:reports"]) + test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do + read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"]) + write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"]) response = conn @@ -1376,7 +1376,7 @@ test "requires write:reports scope", %{conn: conn, id: id, admin: admin} do |> json_response(403) assert response == %{ - "error" => "Insufficient permissions: admin:write:reports | write:reports." + "error" => "Insufficient permissions: admin:write:reports." } conn From 6e88a7e5917f558fe3e9d639297086a9e8b98939 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 20 Jan 2020 21:47:44 +0300 Subject: [PATCH 20/26] exclude blocked user posts from search results --- lib/pleroma/activity.ex | 4 +- lib/pleroma/activity/queries.ex | 10 ++++ lib/pleroma/activity/search.ex | 11 ++-- .../controllers/search_controller.ex | 2 +- .../controllers/search_controller_test.exs | 50 +++++++++++++------ 5 files changed, 56 insertions(+), 21 deletions(-) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 510d3273c..896cbb3c5 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -312,9 +312,7 @@ def restrict_deactivated_users(query) do from(u in User.Query.build(deactivated: true), select: u.ap_id) |> Repo.all() - from(activity in query, - where: activity.actor not in ^deactivated_users - ) + Activity.Queries.exclude_authors(query, deactivated_users) end defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex index 26bc1099d..79f305201 100644 --- a/lib/pleroma/activity/queries.ex +++ b/lib/pleroma/activity/queries.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Activity.Queries do @type query :: Ecto.Queryable.t() | Activity.t() alias Pleroma.Activity + alias Pleroma.User @spec by_ap_id(query, String.t()) :: query def by_ap_id(query \\ Activity, ap_id) do @@ -29,6 +30,11 @@ def by_actor(query \\ Activity, actor) do ) end + @spec by_author(query, String.t()) :: query + def by_author(query \\ Activity, %User{ap_id: ap_id}) do + from(a in query, where: a.actor == ^ap_id) + end + @spec by_object_id(query, String.t() | [String.t()]) :: query def by_object_id(query \\ Activity, object_id) @@ -72,4 +78,8 @@ def exclude_type(query \\ Activity, activity_type) do where: fragment("(?)->>'type' != ?", activity.data, ^activity_type) ) end + + def exclude_authors(query \\ Activity, actors) do + from(activity in query, where: activity.actor not in ^actors) + end end diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex index d30a5a6a5..f96e208da 100644 --- a/lib/pleroma/activity/search.ex +++ b/lib/pleroma/activity/search.ex @@ -26,18 +26,23 @@ def search(user, search_query, options \\ []) do |> query_with(index_type, search_query) |> maybe_restrict_local(user) |> maybe_restrict_author(author) + |> maybe_restrict_blocked(user) |> Pagination.fetch_paginated(%{"offset" => offset, "limit" => limit}, :offset) |> maybe_fetch(user, search_query) end def maybe_restrict_author(query, %User{} = author) do - from([a, o] in query, - where: a.actor == ^author.ap_id - ) + Activity.Queries.by_author(query, author) end def maybe_restrict_author(query, _), do: query + def maybe_restrict_blocked(query, %User{} = user) do + Activity.Queries.exclude_authors(query, User.blocked_users_ap_ids(user)) + end + + def maybe_restrict_blocked(query, _), do: query + defp restrict_public(q) do from([a, o] in q, where: fragment("?->>'type' = 'Create'", a.data), diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 0a929f55b..5a5db8e00 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -43,7 +43,7 @@ defp do_search(version, %{assigns: %{user: user}} = conn, %{"q" => query} = para result = default_values |> Enum.map(fn {resource, default_value} -> - if params["type"] == nil or params["type"] == resource do + if params["type"] in [nil, resource] do {resource, fn -> resource_search(version, resource, query, options) end} else {resource, fn -> default_value end} diff --git a/test/web/mastodon_api/controllers/search_controller_test.exs b/test/web/mastodon_api/controllers/search_controller_test.exs index 7fedf42e5..effae130c 100644 --- a/test/web/mastodon_api/controllers/search_controller_test.exs +++ b/test/web/mastodon_api/controllers/search_controller_test.exs @@ -53,7 +53,8 @@ test "search", %{conn: conn} do {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"}) results = - get(conn, "/api/v2/search", %{"q" => "2hu #private"}) + conn + |> get("/api/v2/search", %{"q" => "2hu #private"}) |> json_response(200) [account | _] = results["accounts"] @@ -73,6 +74,30 @@ test "search", %{conn: conn} do [status] = results["statuses"] assert status["id"] == to_string(activity.id) end + + test "excludes a blocked users from search results", %{conn: conn} do + user = insert(:user) + user_smith = insert(:user, %{nickname: "Agent", name: "I love 2hu"}) + user_neo = insert(:user, %{nickname: "Agent Neo", name: "Agent"}) + + {:ok, act1} = CommonAPI.post(user, %{"status" => "This is about 2hu private 天子"}) + {:ok, act2} = CommonAPI.post(user_smith, %{"status" => "Agent Smith"}) + {:ok, act3} = CommonAPI.post(user_neo, %{"status" => "Agent Smith"}) + Pleroma.User.block(user, user_smith) + + results = + conn + |> assign(:user, user) + |> assign(:token, insert(:oauth_token, user: user, scopes: ["read"])) + |> get("/api/v2/search", %{"q" => "Agent"}) + |> json_response(200) + + status_ids = Enum.map(results["statuses"], fn g -> g["id"] end) + + assert act3.id in status_ids + refute act2.id in status_ids + refute act1.id in status_ids + end end describe ".account_search" do @@ -146,11 +171,10 @@ test "search", %{conn: conn} do {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"}) - conn = + results = conn |> get("/api/v1/search", %{"q" => "2hu"}) - - assert results = json_response(conn, 200) + |> json_response(200) [account | _] = results["accounts"] assert account["id"] == to_string(user_three.id) @@ -168,11 +192,10 @@ test "search fetches remote statuses and prefers them over other results", %{con "status" => "check out https://shitposter.club/notice/2827873" }) - conn = + results = conn |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"}) - - assert results = json_response(conn, 200) + |> json_response(200) [status, %{"id" => ^activity_id}] = results["statuses"] @@ -189,11 +212,10 @@ test "search doesn't show statuses that it shouldn't", %{conn: conn} do }) capture_log(fn -> - conn = + results = conn |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]}) - - assert results = json_response(conn, 200) + |> json_response(200) [] = results["statuses"] end) @@ -202,23 +224,23 @@ test "search doesn't show statuses that it shouldn't", %{conn: conn} do test "search fetches remote accounts", %{conn: conn} do user = insert(:user) - conn = + results = conn |> assign(:user, user) |> assign(:token, insert(:oauth_token, user: user, scopes: ["read"])) |> get("/api/v1/search", %{"q" => "mike@osada.macgirvin.com", "resolve" => "true"}) + |> json_response(200) - assert results = json_response(conn, 200) [account] = results["accounts"] assert account["acct"] == "mike@osada.macgirvin.com" end test "search doesn't fetch remote accounts if resolve is false", %{conn: conn} do - conn = + results = conn |> get("/api/v1/search", %{"q" => "mike@osada.macgirvin.com", "resolve" => "false"}) + |> json_response(200) - assert results = json_response(conn, 200) assert [] == results["accounts"] end From 795a5fe441df28dec60963a6e619dd678d375676 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 21 Jan 2020 19:48:14 +0300 Subject: [PATCH 21/26] Add delete_attachments queue to config --- config/config.exs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index b0036fff0..9be1c721f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -502,7 +502,8 @@ mailer: 10, transmogrifier: 20, scheduled_activities: 10, - background: 5 + background: 5, + attachments_cleanup: 5 ] config :pleroma, :workers, From bc2ebdcfd60e666e9d43ef7b14708ce14f00ad47 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 21 Jan 2020 13:41:22 -0600 Subject: [PATCH 22/26] Update AdminFE build --- .../adminfe/chunk-elementUI.1abbc9b8.css | Bin 0 -> 232660 bytes .../adminfe/chunk-elementUI.a842fb0a.css | Bin 224642 -> 0 bytes priv/static/adminfe/index.html | 2 +- .../static/js/chunk-elementUI.2de79b84.js | Bin 0 -> 663883 bytes .../static/js/chunk-elementUI.2de79b84.js.map | Bin 0 -> 2404935 bytes .../static/js/chunk-elementUI.fa319e7b.js | Bin 638936 -> 0 bytes .../static/js/chunk-elementUI.fa319e7b.js.map | Bin 2312798 -> 0 bytes 7 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 priv/static/adminfe/chunk-elementUI.1abbc9b8.css delete mode 100644 priv/static/adminfe/chunk-elementUI.a842fb0a.css create mode 100644 priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js create mode 100644 priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js.map delete mode 100644 priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js delete mode 100644 priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js.map diff --git a/priv/static/adminfe/chunk-elementUI.1abbc9b8.css b/priv/static/adminfe/chunk-elementUI.1abbc9b8.css new file mode 100644 index 0000000000000000000000000000000000000000..c802d3a400b0401ebf60826905ab9dff79adeb3b GIT binary patch literal 232660 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 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/chunk-elementUI.a842fb0a.css b/priv/static/adminfe/chunk-elementUI.a842fb0a.css deleted file mode 100644 index 3fef5e5fdb26a8762d4ca7ef8be2410ec15c1654..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224642 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 rY}3kDkPzH8JxDaf5|H9;_9$s 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