From 6e4f52f8a2e510273149acbaf629521d1b4aec2e Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 16 Oct 2019 16:16:39 +0200
Subject: [PATCH 01/85] Introduce new ingestion pipeline structure, implement
internal Likes with it.
---
lib/pleroma/web/activity_pub/activity_pub.ex | 35 ++++++++++++
lib/pleroma/web/activity_pub/builder.ex | 43 ++++++++++++++
.../web/activity_pub/object_validator.ex | 57 +++++++++++++++++++
lib/pleroma/web/activity_pub/side_effects.ex | 28 +++++++++
lib/pleroma/web/common_api/common_api.ex | 29 ++++++++--
.../controllers/status_controller.ex | 6 +-
test/notification_test.exs | 8 +--
test/object_test.exs | 3 +-
test/tasks/database_test.exs | 2 +-
test/user_test.exs | 4 +-
.../activity_pub/activity_validator_test.exs | 21 +++++++
test/web/activity_pub/side_effects_test.exs | 32 +++++++++++
test/web/activity_pub/transmogrifier_test.exs | 2 +-
.../activity_pub/views/object_view_test.exs | 2 +-
test/web/common_api/common_api_test.exs | 11 ++--
.../notification_controller_test.exs | 2 +-
.../controllers/status_controller_test.exs | 16 +++---
.../views/notification_view_test.exs | 2 +-
test/web/ostatus/ostatus_controller_test.exs | 4 +-
.../controllers/account_controller_test.exs | 16 +++---
test/web/push/impl_test.exs | 2 +-
test/web/streamer/streamer_test.exs | 6 +-
22 files changed, 284 insertions(+), 47 deletions(-)
create mode 100644 lib/pleroma/web/activity_pub/builder.ex
create mode 100644 lib/pleroma/web/activity_pub/object_validator.ex
create mode 100644 lib/pleroma/web/activity_pub/side_effects.ex
create mode 100644 test/web/activity_pub/activity_validator_test.exs
create mode 100644 test/web/activity_pub/side_effects_test.exs
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 364452b5d..f4fc45926 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -18,6 +18,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.Web.ActivityPub.MRF
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.SideEffects
alias Pleroma.Web.Streamer
alias Pleroma.Web.WebFinger
alias Pleroma.Workers.BackgroundWorker
@@ -123,6 +125,38 @@ def increase_poll_votes_if_vote(%{
def increase_poll_votes_if_vote(_create_data), do: :noop
+ @spec common_pipeline(map(), keyword()) :: {:ok, Activity.t(), keyword()} | {:error, any()}
+ def common_pipeline(object, meta) do
+ with {_, {:ok, validated_object, meta}} <-
+ {:validate_object, ObjectValidator.validate(object, meta)},
+ {_, {:ok, mrfd_object}} <- {:mrf_object, MRF.filter(validated_object)},
+ {_, {:ok, %Activity{} = activity, meta}} <-
+ {:persist_object, persist(mrfd_object, meta)},
+ {_, {:ok, %Activity{} = activity, meta}} <-
+ {:execute_side_effects, SideEffects.handle(activity, meta)} do
+ {:ok, activity, meta}
+ else
+ e -> {:error, e}
+ end
+ end
+
+ # TODO rewrite in with style
+ @spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
+ def persist(object, meta) do
+ local = Keyword.get(meta, :local)
+ {recipients, _, _} = get_recipients(object)
+
+ {:ok, activity} =
+ Repo.insert(%Activity{
+ data: object,
+ local: local,
+ recipients: recipients,
+ actor: object["actor"]
+ })
+
+ {:ok, activity, meta}
+ end
+
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
with nil <- Activity.normalize(map),
map <- lazy_put_activity_defaults(map, fake),
@@ -130,6 +164,7 @@ def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when
{_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map),
{recipients, _, _} = get_recipients(map),
+ # ???
{:fake, false, map, recipients} <- {:fake, fake, map, recipients},
:ok <- Containment.contain_child(map),
{:ok, map, object} <- insert_full_object(map) do
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
new file mode 100644
index 000000000..1787f1510
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -0,0 +1,43 @@
+defmodule Pleroma.Web.ActivityPub.Builder do
+ @moduledoc """
+ This module builds the objects. Meant to be used for creating local objects.
+
+ This module encodes our addressing policies and general shape of our objects.
+ """
+
+ alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.ActivityPub.Visibility
+ alias Pleroma.User
+ alias Pleroma.Object
+
+ @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
+ def like(actor, object) do
+ object_actor = User.get_cached_by_ap_id(object.data["actor"])
+
+ # Address the actor of the object, and our actor's follower collection if the post is public.
+ to =
+ if Visibility.is_public?(object) do
+ [actor.follower_address, object.data["actor"]]
+ else
+ [object.data["actor"]]
+ end
+
+ # CC everyone who's been addressed in the object, except ourself and the object actor's
+ # follower collection
+ cc =
+ (object.data["to"] ++ (object.data["cc"] || []))
+ |> List.delete(actor.ap_id)
+ |> List.delete(object_actor.follower_address)
+
+ {:ok,
+ %{
+ "id" => Utils.generate_activity_id(),
+ "actor" => actor.ap_id,
+ "type" => "Like",
+ "object" => object.data["id"],
+ "to" => to,
+ "cc" => cc,
+ "context" => object.data["context"]
+ }, []}
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
new file mode 100644
index 000000000..8ecad0dec
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validator.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.ActivityPub.ObjectValidator do
+ @moduledoc """
+ This module is responsible for validating an object (which can be an activity)
+ and checking if it is both well formed and also compatible with our view of
+ the system.
+ """
+
+ alias Pleroma.User
+ alias Pleroma.Object
+ alias Pleroma.Web.ActivityPub.Utils
+
+ def validate_id(object, meta) do
+ with {_, true} <- {:id_presence, Map.has_key?(object, "id")} do
+ {:ok, object, meta}
+ else
+ e -> {:error, e}
+ end
+ end
+
+ def validate_actor(object, meta) do
+ with {_, %User{}} <- {:actor_validation, User.get_cached_by_ap_id(object["actor"])} do
+ {:ok, object, meta}
+ else
+ e -> {:error, e}
+ end
+ end
+
+ def common_validations(object, meta) do
+ with {_, {:ok, object, meta}} <- {:validate_id, validate_id(object, meta)},
+ {_, {:ok, object, meta}} <- {:validate_actor, validate_actor(object, meta)} do
+ {:ok, object, meta}
+ else
+ e -> {:error, e}
+ end
+ end
+
+ @spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
+ def validate(object, meta)
+
+ def validate(%{"type" => "Like"} = object, meta) do
+ with {:ok, object, meta} <- common_validations(object, meta),
+ {_, %Object{} = liked_object} <- {:find_liked_object, Object.normalize(object["object"])},
+ {_, nil} <- {:existing_like, Utils.get_existing_like(object["actor"], liked_object)} do
+ {:ok, object, meta}
+ else
+ e -> {:error, e}
+ end
+ end
+
+ def validate(object, meta) do
+ common_validations(object, meta)
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
new file mode 100644
index 000000000..6d3e77a62
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -0,0 +1,28 @@
+defmodule Pleroma.Web.ActivityPub.SideEffects do
+ @moduledoc """
+ This module looks at an inserted object and executes the side effects that it
+ implies. For example, a `Like` activity will increase the like count on the
+ liked object, a `Follow` activity will add the user to the follower
+ collection, and so on.
+ """
+ alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Object
+ alias Pleroma.Notification
+
+ def handle(object, meta \\ [])
+
+ # Tasks this handles:
+ # - Add like to object
+ # - Set up notification
+ def handle(%{data: %{"type" => "Like"}} = object, meta) do
+ liked_object = Object.get_by_ap_id(object.data["object"])
+ Utils.add_like_to_object(object, liked_object)
+ Notification.create_notifications(object)
+ {:ok, object, meta}
+ end
+
+ # Nothing to do
+ def handle(object, meta) do
+ {:ok, object, meta}
+ end
+end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 386408d51..466beb724 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.CommonAPI do
alias Pleroma.ThreadMute
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
@@ -17,6 +18,7 @@ defmodule Pleroma.Web.CommonAPI do
import Pleroma.Web.CommonAPI.Utils
require Pleroma.Constants
+ require Logger
def follow(follower, followed) do
timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout])
@@ -98,16 +100,31 @@ def unrepeat(id_or_ap_id, user) do
end
end
- 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)
+ @spec favorite(User.t(), binary()) :: {:ok, Activity.t()} | {:error, any()}
+ def favorite(%User{} = user, id) do
+ with {_, %Activity{object: object}} <- {:find_object, Activity.get_by_id_with_object(id)},
+ {_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
+ {_, {:ok, %Activity{} = activity, _meta}} <-
+ {:common_pipeline,
+ ActivityPub.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
+ {:ok, activity}
else
- _ -> {:error, dgettext("errors", "Could not favorite")}
+ e ->
+ Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
+ {:error, dgettext("errors", "Could not favorite")}
end
end
+ # 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)
+ # else
+ # _ -> {: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) do
object = Object.normalize(activity)
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
index e5d016f63..4b4482aa8 100644
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -201,9 +201,9 @@ def unreblog(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
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
+ def favourite(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
+ with {:ok, _fav} <- CommonAPI.favorite(user, activity_id),
+ %Activity{} = activity <- Activity.get_by_id(activity_id) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
end
end
diff --git a/test/notification_test.exs b/test/notification_test.exs
index 54c0f9877..940913aa6 100644
--- a/test/notification_test.exs
+++ b/test/notification_test.exs
@@ -431,7 +431,7 @@ test "it does not send notification to mentioned users in likes" do
"status" => "hey @#{other_user.nickname}!"
})
- {:ok, activity_two, _} = CommonAPI.favorite(activity_one.id, third_user)
+ {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
assert other_user not in Notification.get_notified_from_activity(activity_two)
end
@@ -461,7 +461,7 @@ test "liking an activity results in 1 notification, then 0 if the activity is de
assert Enum.empty?(Notification.for_user(user))
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+ {:ok, _} = CommonAPI.favorite(other_user, activity.id)
assert length(Notification.for_user(user)) == 1
@@ -478,7 +478,7 @@ test "liking an activity results in 1 notification, then 0 if the activity is un
assert Enum.empty?(Notification.for_user(user))
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+ {:ok, _} = CommonAPI.favorite(other_user, activity.id)
assert length(Notification.for_user(user)) == 1
@@ -533,7 +533,7 @@ test "liking an activity which is already deleted does not generate a notificati
assert Enum.empty?(Notification.for_user(user))
- {:error, _} = CommonAPI.favorite(activity.id, other_user)
+ {:error, _} = CommonAPI.favorite(other_user, activity.id)
assert Enum.empty?(Notification.for_user(user))
end
diff --git a/test/object_test.exs b/test/object_test.exs
index dd228c32f..353bc388d 100644
--- a/test/object_test.exs
+++ b/test/object_test.exs
@@ -182,7 +182,8 @@ test "preserves internal fields on refetch", %{mock_modified: mock_modified} do
user = insert(:user)
activity = Activity.get_create_by_object_ap_id(object.data["id"])
- {:ok, _activity, object} = CommonAPI.favorite(activity.id, user)
+ {:ok, activity} = CommonAPI.favorite(user, activity.id)
+ object = Object.get_by_ap_id(activity.data["object"])
assert object.data["like_count"] == 1
diff --git a/test/tasks/database_test.exs b/test/tasks/database_test.exs
index b63dcac00..c0a313863 100644
--- a/test/tasks/database_test.exs
+++ b/test/tasks/database_test.exs
@@ -102,7 +102,7 @@ test "it turns OrderedCollection likes into empty arrays" do
{:ok, %{id: id, object: object}} = CommonAPI.post(user, %{"status" => "test"})
{:ok, %{object: object2}} = CommonAPI.post(user, %{"status" => "test test"})
- CommonAPI.favorite(id, user2)
+ CommonAPI.favorite(user2, id)
likes = %{
"first" =>
diff --git a/test/user_test.exs b/test/user_test.exs
index 019e7b400..49c1eb02a 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -1059,8 +1059,8 @@ test "it deletes a user, all follow relationships and all activities", %{user: u
object_two = insert(:note, user: follower)
activity_two = insert(:note_activity, user: follower, note: object_two)
- {:ok, like, _} = CommonAPI.favorite(activity_two.id, user)
- {:ok, like_two, _} = CommonAPI.favorite(activity.id, follower)
+ {:ok, like} = CommonAPI.favorite(user, activity_two.id)
+ {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
{:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user)
{:ok, job} = User.delete(user)
diff --git a/test/web/activity_pub/activity_validator_test.exs b/test/web/activity_pub/activity_validator_test.exs
new file mode 100644
index 000000000..cb0895a81
--- /dev/null
+++ b/test/web/activity_pub/activity_validator_test.exs
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
+ use Pleroma.DataCase
+
+ import Pleroma.Factory
+
+ describe "likes" do
+ test "it is well formed" do
+ _required_fields = [
+ "id",
+ "actor",
+ "object"
+ ]
+
+ _user = insert(:user)
+ end
+ end
+end
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
new file mode 100644
index 000000000..e505ab4dd
--- /dev/null
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -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.ActivityPub.SideEffectsTest do
+ use Pleroma.DataCase
+ alias Pleroma.Object
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.ActivityPub.Builder
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.SideEffects
+
+ import Pleroma.Factory
+ describe "like objects" do
+ setup do
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(user, %{"status" => "hey"})
+
+ {:ok, like_data, _meta} = Builder.like(user, post.object)
+ {:ok, like, _meta} = ActivityPub.persist(like_data, [])
+
+ %{like: like, user: user}
+ end
+
+ test "add the like to the original object", %{like: like, user: user} do
+ {:ok, like, _} = SideEffects.handle(like)
+ object = Object.get_by_ap_id(like.data["object"])
+ assert object.data["like_count"] == 1
+ assert user.ap_id in object.data["likes"]
+ end
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 6c35a6f4d..28edc5508 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -1187,7 +1187,7 @@ test "it translates ostatus IDs to external URLs" do
user = insert(:user)
- {:ok, activity, _} = CommonAPI.favorite(referent_activity.id, user)
+ {:ok, activity} = CommonAPI.favorite(user, referent_activity.id)
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
assert modified["object"] == "http://gs.example.org:4040/index.php/notice/29"
diff --git a/test/web/activity_pub/views/object_view_test.exs b/test/web/activity_pub/views/object_view_test.exs
index 13447dc29..998247c5c 100644
--- a/test/web/activity_pub/views/object_view_test.exs
+++ b/test/web/activity_pub/views/object_view_test.exs
@@ -41,7 +41,7 @@ test "renders a like activity" do
object = Object.normalize(note)
user = insert(:user)
- {:ok, like_activity, _} = CommonAPI.favorite(note.id, user)
+ {:ok, like_activity} = CommonAPI.favorite(user, note.id)
result = ObjectView.render("object.json", %{object: like_activity})
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 83df44c36..d46a361c5 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -251,9 +251,12 @@ test "favoriting a status" do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
+ {:ok, post_activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
- {:ok, %Activity{}, _} = CommonAPI.favorite(activity.id, user)
+ {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
+ assert data["type"] == "Like"
+ assert data["actor"] == user.ap_id
+ assert data["object"] == post_activity.data["object"]
end
test "retweeting a status twice returns an error" do
@@ -270,8 +273,8 @@ test "favoriting a status twice returns an error" do
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{}} = CommonAPI.favorite(user, activity.id)
+ {:error, _} = CommonAPI.favorite(user, activity.id)
end
end
diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs
index e4137e92c..6eadccb8e 100644
--- a/test/web/mastodon_api/controllers/notification_controller_test.exs
+++ b/test/web/mastodon_api/controllers/notification_controller_test.exs
@@ -143,7 +143,7 @@ test "filters notifications using exclude_types", %{conn: conn} do
{: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, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
{:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs
index 2de2725e0..1414d9fed 100644
--- a/test/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/web/mastodon_api/controllers/status_controller_test.exs
@@ -589,7 +589,7 @@ test "reblogged status for another user", %{conn: conn} do
user1 = insert(:user)
user2 = insert(:user)
user3 = insert(:user)
- CommonAPI.favorite(activity.id, user2)
+ {:ok, _} = CommonAPI.favorite(user2, activity.id)
{: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)
@@ -695,7 +695,7 @@ test "unfavorites a status and returns it", %{conn: conn} do
activity = insert(:note_activity)
user = insert(:user)
- {:ok, _, _} = CommonAPI.favorite(activity.id, user)
+ {:ok, _} = CommonAPI.favorite(user, activity.id)
conn =
conn
@@ -1047,7 +1047,7 @@ test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{c
test "returns users who have favorited the status", %{conn: conn, activity: activity} do
other_user = insert(:user)
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+ {:ok, _} = CommonAPI.favorite(other_user, activity.id)
response =
conn
@@ -1078,7 +1078,7 @@ test "does not return users who have favorited the status but are blocked", %{
other_user = insert(:user)
{:ok, user} = User.block(user, other_user)
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+ {:ok, _} = CommonAPI.favorite(other_user, activity.id)
response =
conn
@@ -1091,7 +1091,7 @@ test "does not return users who have favorited the status but are blocked", %{
test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
other_user = insert(:user)
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+ {:ok, _} = CommonAPI.favorite(other_user, activity.id)
response =
conn
@@ -1112,7 +1112,7 @@ test "requires authentification for private posts", %{conn: conn, user: user} do
"visibility" => "direct"
})
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+ {:ok, _} = CommonAPI.favorite(other_user, activity.id)
conn
|> assign(:user, nil)
@@ -1269,7 +1269,7 @@ test "returns the favorites of a user", %{conn: conn} do
{:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
- {:ok, _, _} = CommonAPI.favorite(activity.id, user)
+ {:ok, _} = CommonAPI.favorite(user, activity.id)
first_conn =
conn
@@ -1289,7 +1289,7 @@ test "returns the favorites of a user", %{conn: conn} do
"Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
})
- {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
+ {:ok, _} = CommonAPI.favorite(user, second_activity.id)
last_like = status["id"]
diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs
index c9043a69a..d06809268 100644
--- a/test/web/mastodon_api/views/notification_view_test.exs
+++ b/test/web/mastodon_api/views/notification_view_test.exs
@@ -42,7 +42,7 @@ test "Favourite notification" do
user = insert(:user)
another_user = insert(:user)
{:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
- {:ok, favorite_activity, _object} = CommonAPI.favorite(create_activity.id, another_user)
+ {:ok, favorite_activity} = CommonAPI.favorite(another_user, create_activity.id)
{:ok, [notification]} = Notification.create_notifications(favorite_activity)
create_activity = Activity.get_by_id(create_activity.id)
diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs
index b1af918d8..7aee16e2c 100644
--- a/test/web/ostatus/ostatus_controller_test.exs
+++ b/test/web/ostatus/ostatus_controller_test.exs
@@ -271,7 +271,7 @@ test "only gets a notice in AS2 format for Create messages", %{conn: conn} do
user = insert(:user)
- {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user)
+ {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
url = "/notice/#{like_activity.id}"
assert like_activity.data["type"] == "Like"
@@ -298,7 +298,7 @@ test "render html for redirect for html format", %{conn: conn} do
user = insert(:user)
- {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user)
+ {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
assert like_activity.data["type"] == "Like"
diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs
index 3b4665afd..6a6135d02 100644
--- a/test/web/pleroma_api/controllers/account_controller_test.exs
+++ b/test/web/pleroma_api/controllers/account_controller_test.exs
@@ -165,7 +165,7 @@ test "returns list of statuses favorited by specified user", %{
user: user
} do
[activity | _] = insert_pair(:note_activity)
- CommonAPI.favorite(activity.id, user)
+ CommonAPI.favorite(user, activity.id)
response =
conn
@@ -184,7 +184,7 @@ test "returns favorites for specified user_id when user is not logged in", %{
user: user
} do
activity = insert(:note_activity)
- CommonAPI.favorite(activity.id, user)
+ CommonAPI.favorite(user, activity.id)
response =
conn
@@ -205,7 +205,7 @@ test "returns favorited DM only when user is logged in and he is one of recipien
"visibility" => "direct"
})
- CommonAPI.favorite(direct.id, user)
+ CommonAPI.favorite(user, direct.id)
response =
conn
@@ -236,7 +236,7 @@ test "does not return others' favorited DM when user is not one of recipients",
"visibility" => "direct"
})
- CommonAPI.favorite(direct.id, user)
+ CommonAPI.favorite(user, direct.id)
response =
conn
@@ -255,7 +255,7 @@ test "paginates favorites using since_id and max_id", %{
activities = insert_list(10, :note_activity)
Enum.each(activities, fn activity ->
- CommonAPI.favorite(activity.id, user)
+ CommonAPI.favorite(user, activity.id)
end)
third_activity = Enum.at(activities, 2)
@@ -283,7 +283,7 @@ test "limits favorites using limit parameter", %{
7
|> insert_list(:note_activity)
|> Enum.each(fn activity ->
- CommonAPI.favorite(activity.id, user)
+ CommonAPI.favorite(user, activity.id)
end)
response =
@@ -321,7 +321,7 @@ test "returns 403 error when user has hidden own favorites", %{
} do
user = insert(:user, %{info: %{hide_favorites: true}})
activity = insert(:note_activity)
- CommonAPI.favorite(activity.id, user)
+ CommonAPI.favorite(user, activity.id)
conn =
conn
@@ -334,7 +334,7 @@ test "returns 403 error when user has hidden own favorites", %{
test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
user = insert(:user)
activity = insert(:note_activity)
- CommonAPI.favorite(activity.id, user)
+ CommonAPI.favorite(user, activity.id)
conn =
conn
diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs
index 2f6ce4bd2..36c69c7c9 100644
--- a/test/web/push/impl_test.exs
+++ b/test/web/push/impl_test.exs
@@ -152,7 +152,7 @@ test "renders body for like activity" do
"Lorem ipsum dolor sit amet, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
})
- {:ok, activity, _} = CommonAPI.favorite(activity.id, user)
+ {:ok, activity} = CommonAPI.favorite(user, activity.id)
object = Object.normalize(activity)
assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post"
diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs
index d33eb1e42..b363935a2 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/web/streamer/streamer_test.exs
@@ -68,7 +68,7 @@ test "it doesn't send notify to the 'user:notification' stream when a user is bl
)
{:ok, activity} = CommonAPI.post(user, %{"status" => ":("})
- {:ok, notif, _} = CommonAPI.favorite(activity.id, blocked)
+ {:ok, notif} = CommonAPI.favorite(blocked, activity.id)
Streamer.stream("user:notification", notif)
Task.await(task)
@@ -87,7 +87,7 @@ test "it doesn't send notify to the 'user:notification' stream when a thread is
{:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
{:ok, activity} = CommonAPI.add_mute(user, activity)
- {:ok, notif, _} = CommonAPI.favorite(activity.id, user2)
+ {:ok, notif} = CommonAPI.favorite(user2, activity.id)
Streamer.stream("user:notification", notif)
Task.await(task)
end
@@ -105,7 +105,7 @@ test "it doesn't send notify to the 'user:notification' stream' when a domain is
{:ok, user} = User.block_domain(user, "hecking-lewd-place.com")
{:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
- {:ok, notif, _} = CommonAPI.favorite(activity.id, user2)
+ {:ok, notif} = CommonAPI.favorite(user2, activity.id)
Streamer.stream("user:notification", notif)
Task.await(task)
From 081e8206ab75e336a76b621508b3999170159ec6 Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 16 Oct 2019 17:03:21 +0200
Subject: [PATCH 02/85] Transmogrifier: Use new ingestion pipeline for Likes.
---
lib/pleroma/object/containment.ex | 12 +++++++
.../web/activity_pub/object_validator.ex | 5 +--
.../web/activity_pub/transmogrifier.ex | 31 +++++++++++++++----
3 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex
index f077a9f32..edbe92381 100644
--- a/lib/pleroma/object/containment.ex
+++ b/lib/pleroma/object/containment.ex
@@ -32,6 +32,18 @@ def get_actor(%{"actor" => nil, "attributedTo" => actor}) when not is_nil(actor)
get_actor(%{"actor" => actor})
end
+ def get_object(%{"object" => id}) when is_binary(id) do
+ id
+ end
+
+ def get_object(%{"object" => %{"id" => id}}) when is_binary(id) do
+ id
+ end
+
+ def get_object(_) do
+ nil
+ end
+
@doc """
Checks that an imported AP object's actor matches the domain it came from.
"""
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 8ecad0dec..0048cc4ec 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -31,7 +31,7 @@ def validate_actor(object, meta) do
def common_validations(object, meta) do
with {_, {:ok, object, meta}} <- {:validate_id, validate_id(object, meta)},
- {_, {:ok, object, meta}} <- {:validate_actor, validate_actor(object, meta)} do
+ {_, {:ok, object, meta}} <- {:validate_actor, validate_actor(object, meta)} do
{:ok, object, meta}
else
e -> {:error, e}
@@ -43,7 +43,8 @@ def validate(object, meta)
def validate(%{"type" => "Like"} = object, meta) do
with {:ok, object, meta} <- common_validations(object, meta),
- {_, %Object{} = liked_object} <- {:find_liked_object, Object.normalize(object["object"])},
+ {_, %Object{} = liked_object} <-
+ {:find_liked_object, Object.normalize(object["object"])},
{_, nil} <- {:existing_like, Utils.get_existing_like(object["actor"], liked_object)} do
{:ok, object, meta}
else
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index b56343beb..3e982adcb 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -563,19 +563,38 @@ def handle_incoming(
end
def handle_incoming(
- %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data,
+ %{"type" => "Like", "object" => _object_id, "actor" => _actor, "id" => _id} = data,
_options
) do
- with actor <- Containment.get_actor(data),
- {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
- {:ok, object} <- get_obj_helper(object_id),
- {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
+ with data <- Map.take(data, ["type", "object", "actor", "context", "id"]),
+ actor <- Containment.get_actor(data),
+ object <- Containment.get_object(data),
+ data <- data |> Map.put("actor", actor) |> Map.put("object", object),
+ _user <- User.get_or_fetch_by_ap_id(actor),
+ object <- Object.normalize(object),
+ data <- Map.put_new(data, "context", object.data["context"]),
+ {_, {:ok, activity, _meta}} <-
+ {:common_pipeline, ActivityPub.common_pipeline(data, local: false)} do
{:ok, activity}
else
- _e -> :error
+ e -> {:error, e}
end
end
+ # def handle_incoming(
+ # %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data,
+ # _options
+ # ) do
+ # with actor <- Containment.get_actor(data),
+ # {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
+ # {:ok, object} <- get_obj_helper(object_id),
+ # {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
+ # {:ok, activity}
+ # else
+ # _e -> :error
+ # end
+ # end
+
def handle_incoming(
%{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data,
_options
From 66452f518faa1f079f02006943b0c2cdc830b47f Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 17 Oct 2019 18:36:52 +0200
Subject: [PATCH 03/85] ObjectValidator: Rewrite LikeValidator with Ecto.
---
.../web/activity_pub/object_validator.ex | 42 ++--------
.../object_validators/like_validator.ex | 69 ++++++++++++++++
.../object_validators/types/object.ex | 25 ++++++
lib/pleroma/web/common_api/common_api.ex | 10 ---
.../activity_pub/activity_validator_test.exs | 21 -----
.../activity_pub/object_validator_test.exs | 80 +++++++++++++++++++
test/web/activity_pub/side_effects_test.exs | 1 +
7 files changed, 183 insertions(+), 65 deletions(-)
create mode 100644 lib/pleroma/web/activity_pub/object_validators/like_validator.ex
create mode 100644 lib/pleroma/web/activity_pub/object_validators/types/object.ex
delete mode 100644 test/web/activity_pub/activity_validator_test.exs
create mode 100644 test/web/activity_pub/object_validator_test.exs
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 0048cc4ec..adcb53c65 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -9,50 +9,24 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
the system.
"""
- alias Pleroma.User
- alias Pleroma.Object
- alias Pleroma.Web.ActivityPub.Utils
-
- def validate_id(object, meta) do
- with {_, true} <- {:id_presence, Map.has_key?(object, "id")} do
- {:ok, object, meta}
- else
- e -> {:error, e}
- end
- end
-
- def validate_actor(object, meta) do
- with {_, %User{}} <- {:actor_validation, User.get_cached_by_ap_id(object["actor"])} do
- {:ok, object, meta}
- else
- e -> {:error, e}
- end
- end
-
- def common_validations(object, meta) do
- with {_, {:ok, object, meta}} <- {:validate_id, validate_id(object, meta)},
- {_, {:ok, object, meta}} <- {:validate_actor, validate_actor(object, meta)} do
- {:ok, object, meta}
- else
- e -> {:error, e}
- end
- end
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
def validate(object, meta)
def validate(%{"type" => "Like"} = object, meta) do
- with {:ok, object, meta} <- common_validations(object, meta),
- {_, %Object{} = liked_object} <-
- {:find_liked_object, Object.normalize(object["object"])},
- {_, nil} <- {:existing_like, Utils.get_existing_like(object["actor"], liked_object)} do
+ with {_, %{valid?: true, changes: object}} <-
+ {:validate_object, LikeValidator.cast_and_validate(object)} do
+ object = stringify_keys(object)
{:ok, object, meta}
else
e -> {:error, e}
end
end
- def validate(object, meta) do
- common_validations(object, meta)
+ defp stringify_keys(object) do
+ object
+ |> Enum.map(fn {key, val} -> {to_string(key), val} end)
+ |> Enum.into(%{})
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
new file mode 100644
index 000000000..d5a2f7202
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
@@ -0,0 +1,69 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
+ use Ecto.Schema
+ import Ecto.Changeset
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+ alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.User
+ alias Pleroma.Object
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, :string, primary_key: true)
+ field(:type, :string)
+ field(:object, Types.ObjectID)
+ field(:actor, Types.ObjectID)
+ field(:context, :string)
+ field(:to, {:array, :string})
+ field(:cc, {:array, :string})
+ end
+
+ def cast_and_validate(data) do
+ data
+ |> cast_data()
+ |> validate_data()
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> cast(data, [:id, :type, :object, :actor, :context, :to, :cc])
+ end
+
+ def validate_data(data_cng) do
+ data_cng
+ |> validate_inclusion(:type, ["Like"])
+ |> validate_required([:id, :type, :object, :actor, :context])
+ |> validate_change(:actor, &actor_valid?/2)
+ |> validate_change(:object, &object_valid?/2)
+ |> validate_existing_like()
+ end
+
+ def validate_existing_like(%{changes: %{actor: actor, object: object}} = cng) do
+ if Utils.get_existing_like(actor, %{data: %{"id" => object}}) do
+ cng
+ |> add_error(:actor, "already liked this object")
+ |> add_error(:object, "already liked by this actor")
+ else
+ cng
+ end
+ end
+
+ def validate_existing_like(cng), do: cng
+
+ def actor_valid?(field_name, actor) do
+ if User.get_cached_by_ap_id(actor) do
+ []
+ else
+ [{field_name, "can't find user"}]
+ end
+ end
+
+ def object_valid?(field_name, object) do
+ if Object.get_cached_by_ap_id(object) do
+ []
+ else
+ [{field_name, "can't find object"}]
+ end
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/object.ex b/lib/pleroma/web/activity_pub/object_validators/types/object.ex
new file mode 100644
index 000000000..92fc13ba8
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/types/object.ex
@@ -0,0 +1,25 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID do
+ use Ecto.Type
+
+ def type, do: :string
+
+ def cast(object) when is_binary(object) do
+ {:ok, object}
+ end
+
+ def cast(%{"id" => object}) when is_binary(object) do
+ {:ok, object}
+ end
+
+ def cast(_) do
+ :error
+ end
+
+ def dump(data) do
+ {:ok, data}
+ end
+
+ def load(data) do
+ {:ok, data}
+ end
+end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 466beb724..e0b22a314 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -115,16 +115,6 @@ def favorite(%User{} = user, id) do
end
end
- # 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)
- # else
- # _ -> {: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) do
object = Object.normalize(activity)
diff --git a/test/web/activity_pub/activity_validator_test.exs b/test/web/activity_pub/activity_validator_test.exs
deleted file mode 100644
index cb0895a81..000000000
--- a/test/web/activity_pub/activity_validator_test.exs
+++ /dev/null
@@ -1,21 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
- use Pleroma.DataCase
-
- import Pleroma.Factory
-
- describe "likes" do
- test "it is well formed" do
- _required_fields = [
- "id",
- "actor",
- "object"
- ]
-
- _user = insert(:user)
- end
- end
-end
diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs
new file mode 100644
index 000000000..374a7c0df
--- /dev/null
+++ b/test/web/activity_pub/object_validator_test.exs
@@ -0,0 +1,80 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
+ alias Pleroma.Web.ActivityPub.Utils
+ import Pleroma.Factory
+
+ describe "likes" do
+ setup do
+ user = insert(:user)
+ {:ok, post_activity} = CommonAPI.post(user, %{"status" => "uguu"})
+
+ valid_like = %{
+ "type" => "Like",
+ "id" => Utils.generate_activity_id(),
+ "object" => post_activity.data["object"],
+ "actor" => user.ap_id,
+ "context" => "a context"
+ }
+
+ %{valid_like: valid_like, user: user, post_activity: post_activity}
+ end
+
+ test "returns ok when called in the ObjectValidator", %{valid_like: valid_like} do
+ {:ok, object, _meta} = ObjectValidator.validate(valid_like, [])
+
+ assert "id" in Map.keys(object)
+ end
+
+ test "is valid for a valid object", %{valid_like: valid_like} do
+ assert LikeValidator.cast_and_validate(valid_like).valid?
+ end
+
+ test "it errors when the actor is missing or not known", %{valid_like: valid_like} do
+ without_actor = Map.delete(valid_like, "actor")
+
+ refute LikeValidator.cast_and_validate(without_actor).valid?
+
+ with_invalid_actor = Map.put(valid_like, "actor", "invalidactor")
+
+ refute LikeValidator.cast_and_validate(with_invalid_actor).valid?
+ end
+
+ test "it errors when the object is missing or not known", %{valid_like: valid_like} do
+ without_object = Map.delete(valid_like, "object")
+
+ refute LikeValidator.cast_and_validate(without_object).valid?
+
+ with_invalid_object = Map.put(valid_like, "object", "invalidobject")
+
+ refute LikeValidator.cast_and_validate(with_invalid_object).valid?
+ end
+
+ test "it errors when the actor has already like the object", %{
+ valid_like: valid_like,
+ user: user,
+ post_activity: post_activity
+ } do
+ _like = CommonAPI.favorite(user, post_activity.id)
+
+ refute LikeValidator.cast_and_validate(valid_like).valid?
+ end
+
+ test "it works when actor or object are wrapped in maps", %{valid_like: valid_like} do
+ wrapped_like =
+ valid_like
+ |> Map.put("actor", %{"id" => valid_like["actor"]})
+ |> Map.put("object", %{"id" => valid_like["object"]})
+
+ validated = LikeValidator.cast_and_validate(wrapped_like)
+
+ assert validated.valid?
+
+ assert {:actor, valid_like["actor"]} in validated.changes
+ assert {:object, valid_like["object"]} in validated.changes
+ end
+ end
+end
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
index e505ab4dd..9d99e05a0 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
alias Pleroma.Web.ActivityPub.SideEffects
import Pleroma.Factory
+
describe "like objects" do
setup do
user = insert(:user)
From 203d61b95012fd2cb8a8618f6f51a3748c940cc1 Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 17 Oct 2019 19:35:31 +0200
Subject: [PATCH 04/85] Transmogrifier: Make proper use of the LikeValidator.
---
.../web/activity_pub/object_validator.ex | 10 ++-
.../object_validators/like_validator.ex | 2 +-
.../web/activity_pub/transmogrifier.ex | 79 +++++++++++++------
.../activity_pub/object_validator_test.exs | 2 +
test/web/activity_pub/transmogrifier_test.exs | 4 +-
5 files changed, 68 insertions(+), 29 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index adcb53c65..33e67dbb9 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -10,6 +10,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
"""
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
+ alias Pleroma.User
+ alias Pleroma.Object
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
def validate(object, meta)
@@ -24,9 +26,15 @@ def validate(%{"type" => "Like"} = object, meta) do
end
end
- defp stringify_keys(object) do
+ def stringify_keys(object) do
object
|> Enum.map(fn {key, val} -> {to_string(key), val} end)
|> Enum.into(%{})
end
+
+ def fetch_actor_and_object(object) do
+ User.get_or_fetch_by_ap_id(object["actor"])
+ Object.normalize(object["object"])
+ :ok
+ end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
index d5a2f7202..e6a5aaca8 100644
--- a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
@@ -33,7 +33,7 @@ def cast_data(data) do
def validate_data(data_cng) do
data_cng
|> validate_inclusion(:type, ["Like"])
- |> validate_required([:id, :type, :object, :actor, :context])
+ |> validate_required([:id, :type, :object, :actor, :context, :to, :cc])
|> validate_change(:actor, &actor_valid?/2)
|> validate_change(:object, &object_valid?/2)
|> validate_existing_like()
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 3e982adcb..591d7aa94 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -16,6 +16,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
alias Pleroma.Workers.TransmogrifierWorker
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
import Ecto.Query
@@ -562,39 +564,21 @@ def handle_incoming(
end
end
- def handle_incoming(
- %{"type" => "Like", "object" => _object_id, "actor" => _actor, "id" => _id} = data,
- _options
- ) do
- with data <- Map.take(data, ["type", "object", "actor", "context", "id"]),
- actor <- Containment.get_actor(data),
- object <- Containment.get_object(data),
- data <- data |> Map.put("actor", actor) |> Map.put("object", object),
- _user <- User.get_or_fetch_by_ap_id(actor),
- object <- Object.normalize(object),
- data <- Map.put_new(data, "context", object.data["context"]),
+ def handle_incoming(%{"type" => "Like"} = data, _options) do
+ with {_, %{changes: cast_data}} <- {:casting_data, LikeValidator.cast_data(data)},
+ cast_data <- ObjectValidator.stringify_keys(cast_data),
+ :ok <- ObjectValidator.fetch_actor_and_object(cast_data),
+ {_, {:ok, cast_data}} <- {:maybe_add_context, maybe_add_context_from_object(cast_data)},
+ {_, {:ok, cast_data}} <-
+ {:maybe_add_recipients, maybe_add_recipients_from_object(cast_data)},
{_, {:ok, activity, _meta}} <-
- {:common_pipeline, ActivityPub.common_pipeline(data, local: false)} do
+ {:common_pipeline, ActivityPub.common_pipeline(cast_data, local: false)} do
{:ok, activity}
else
e -> {:error, e}
end
end
- # def handle_incoming(
- # %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data,
- # _options
- # ) do
- # with actor <- Containment.get_actor(data),
- # {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
- # {:ok, object} <- get_obj_helper(object_id),
- # {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
- # {:ok, activity}
- # else
- # _e -> :error
- # end
- # end
-
def handle_incoming(
%{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data,
_options
@@ -1156,4 +1140,47 @@ def maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do
def maybe_fix_user_url(data), do: data
def maybe_fix_user_object(data), do: maybe_fix_user_url(data)
+
+ defp maybe_add_context_from_object(%{"context" => context} = data) when is_binary(context),
+ do: {:ok, data}
+
+ defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(object) do
+ if object = Object.normalize(object) do
+ data =
+ data
+ |> Map.put("context", object.data["context"])
+
+ {:ok, data}
+ else
+ {:error, "No context on referenced object"}
+ end
+ end
+
+ defp maybe_add_context_from_object(_) do
+ {:error, "No referenced object"}
+ end
+
+ defp maybe_add_recipients_from_object(%{"object" => object} = data) do
+ to = data["to"] || []
+ cc = data["cc"] || []
+
+ if to == [] && cc == [] do
+ if object = Object.normalize(object) do
+ data =
+ data
+ |> Map.put("to", [object.data["actor"]])
+ |> Map.put("cc", cc)
+
+ {:ok, data}
+ else
+ {:error, "No actor on referenced object"}
+ end
+ else
+ {:ok, data}
+ end
+ end
+
+ defp maybe_add_recipients_from_object(_) do
+ {:error, "No referenced object"}
+ end
end
diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs
index 374a7c0df..2292db6d7 100644
--- a/test/web/activity_pub/object_validator_test.exs
+++ b/test/web/activity_pub/object_validator_test.exs
@@ -13,6 +13,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
{:ok, post_activity} = CommonAPI.post(user, %{"status" => "uguu"})
valid_like = %{
+ "to" => [user.ap_id],
+ "cc" => [],
"type" => "Like",
"id" => Utils.generate_activity_id(),
"object" => post_activity.data["object"],
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 28edc5508..e5d4dcd64 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -333,7 +333,9 @@ test "it works for incoming likes" do
|> Poison.decode!()
|> Map.put("object", activity.data["object"])
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ refute Enum.empty?(activity.recipients)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Like"
From 4ec299ea9c1cf45c42e98d7b33f33a72f5e7a9c0 Mon Sep 17 00:00:00 2001
From: lain
Date: Fri, 18 Oct 2019 12:11:25 +0200
Subject: [PATCH 05/85] CommonAPI tests: Capture logs.
---
test/web/common_api/common_api_test.exs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index d46a361c5..63d7ea79f 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.CommonAPITest do
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
+ import ExUnit.CaptureLog
require Pleroma.Constants
@@ -274,7 +275,9 @@ test "favoriting a status twice returns an error" do
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
{:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
- {:error, _} = CommonAPI.favorite(user, activity.id)
+ assert capture_log(fn ->
+ assert {:error, _} = CommonAPI.favorite(user, activity.id)
+ end) =~ "[error]"
end
end
From 15bbc34c079018f1c988fe9d445bec50e85bbeaf Mon Sep 17 00:00:00 2001
From: lain
Date: Fri, 18 Oct 2019 12:44:53 +0200
Subject: [PATCH 06/85] Tests: Capture log.
---
test/notification_test.exs | 6 +++++-
test/web/common_api/common_api_test.exs | 5 +++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/test/notification_test.exs b/test/notification_test.exs
index 940913aa6..480c9415b 100644
--- a/test/notification_test.exs
+++ b/test/notification_test.exs
@@ -14,6 +14,8 @@ defmodule Pleroma.NotificationTest do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Streamer
+ import ExUnit.CaptureLog
+
describe "create_notifications" do
test "notifies someone when they are directly addressed" do
user = insert(:user)
@@ -533,7 +535,9 @@ test "liking an activity which is already deleted does not generate a notificati
assert Enum.empty?(Notification.for_user(user))
- {:error, _} = CommonAPI.favorite(other_user, activity.id)
+ assert capture_log(fn ->
+ {:error, _} = CommonAPI.favorite(other_user, activity.id)
+ end) =~ "[error]"
assert Enum.empty?(Notification.for_user(user))
end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 63d7ea79f..8195b1910 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -275,9 +275,10 @@ test "favoriting a status twice returns an error" do
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
{:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
+
assert capture_log(fn ->
- assert {:error, _} = CommonAPI.favorite(user, activity.id)
- end) =~ "[error]"
+ assert {:error, _} = CommonAPI.favorite(user, activity.id)
+ end) =~ "[error]"
end
end
From f1381d68e740daf4c341359a2b5837bc2bd3a051 Mon Sep 17 00:00:00 2001
From: lain
Date: Sat, 19 Oct 2019 14:46:14 +0200
Subject: [PATCH 07/85] StatusControllerTest: Capture log.
---
.../controllers/status_controller_test.exs | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs
index 1414d9fed..2bbd8a151 100644
--- a/test/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/web/mastodon_api/controllers/status_controller_test.exs
@@ -17,6 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
+ import ExUnit.CaptureLog
describe "posting statuses" do
setup do
@@ -681,12 +682,14 @@ test "favs a status and returns it", %{conn: conn} do
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 capture_log(fn ->
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/1/favourite")
- assert json_response(conn, 400) == %{"error" => "Could not favorite"}
+ assert json_response(conn, 400) == %{"error" => "Could not favorite"}
+ end) =~ "[error]"
end
end
From 97d5c79aa07bfe836cd676424ce1b5a298c72b60 Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 23 Oct 2019 11:52:27 +0200
Subject: [PATCH 08/85] Add Pipeline module, test for federation.
---
lib/pleroma/web/activity_pub/activity_pub.ex | 19 +---
lib/pleroma/web/activity_pub/pipeline.ex | 41 +++++++++
.../web/activity_pub/transmogrifier.ex | 7 +-
lib/pleroma/web/common_api/common_api.ex | 3 +-
test/web/activity_pub/pipeline_test.exs | 87 +++++++++++++++++++
5 files changed, 135 insertions(+), 22 deletions(-)
create mode 100644 lib/pleroma/web/activity_pub/pipeline.ex
create mode 100644 test/web/activity_pub/pipeline_test.exs
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index f4fc45926..0789ec31c 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -18,8 +18,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.Web.ActivityPub.MRF
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.Web.ActivityPub.ObjectValidator
- alias Pleroma.Web.ActivityPub.SideEffects
alias Pleroma.Web.Streamer
alias Pleroma.Web.WebFinger
alias Pleroma.Workers.BackgroundWorker
@@ -125,25 +123,10 @@ def increase_poll_votes_if_vote(%{
def increase_poll_votes_if_vote(_create_data), do: :noop
- @spec common_pipeline(map(), keyword()) :: {:ok, Activity.t(), keyword()} | {:error, any()}
- def common_pipeline(object, meta) do
- with {_, {:ok, validated_object, meta}} <-
- {:validate_object, ObjectValidator.validate(object, meta)},
- {_, {:ok, mrfd_object}} <- {:mrf_object, MRF.filter(validated_object)},
- {_, {:ok, %Activity{} = activity, meta}} <-
- {:persist_object, persist(mrfd_object, meta)},
- {_, {:ok, %Activity{} = activity, meta}} <-
- {:execute_side_effects, SideEffects.handle(activity, meta)} do
- {:ok, activity, meta}
- else
- e -> {:error, e}
- end
- end
-
# TODO rewrite in with style
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
def persist(object, meta) do
- local = Keyword.get(meta, :local)
+ local = Keyword.fetch!(meta, :local)
{recipients, _, _} = get_recipients(object)
{:ok, activity} =
diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
new file mode 100644
index 000000000..cb3571917
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -0,0 +1,41 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Pipeline do
+ alias Pleroma.Activity
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.MRF
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.SideEffects
+ alias Pleroma.Web.Federator
+
+ @spec common_pipeline(map(), keyword()) :: {:ok, Activity.t(), keyword()} | {:error, any()}
+ def common_pipeline(object, meta) do
+ with {_, {:ok, validated_object, meta}} <-
+ {:validate_object, ObjectValidator.validate(object, meta)},
+ {_, {:ok, mrfd_object}} <- {:mrf_object, MRF.filter(validated_object)},
+ {_, {:ok, %Activity{} = activity, meta}} <-
+ {:persist_object, ActivityPub.persist(mrfd_object, meta)},
+ {_, {:ok, %Activity{} = activity, meta}} <-
+ {:execute_side_effects, SideEffects.handle(activity, meta)},
+ {_, {:ok, _}} <- {:federation, maybe_federate(activity, meta)} do
+ {:ok, activity, meta}
+ else
+ e -> {:error, e}
+ end
+ end
+
+ defp maybe_federate(activity, meta) do
+ with {:ok, local} <- Keyword.fetch(meta, :local) do
+ if local do
+ Federator.publish(activity)
+ {:ok, :federated}
+ else
+ {:ok, :not_federated}
+ end
+ else
+ _e -> {:error, "local not set in meta"}
+ end
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 591d7aa94..4dd884ce9 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -12,12 +12,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
+ alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
alias Pleroma.Workers.TransmogrifierWorker
- alias Pleroma.Web.ActivityPub.ObjectValidator
- alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
import Ecto.Query
@@ -572,7 +573,7 @@ def handle_incoming(%{"type" => "Like"} = data, _options) do
{_, {:ok, cast_data}} <-
{:maybe_add_recipients, maybe_add_recipients_from_object(cast_data)},
{_, {:ok, activity, _meta}} <-
- {:common_pipeline, ActivityPub.common_pipeline(cast_data, local: false)} do
+ {:common_pipeline, Pipeline.common_pipeline(cast_data, local: false)} do
{:ok, activity}
else
e -> {:error, e}
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index e0b22a314..535a48dcc 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.CommonAPI do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
+ alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
@@ -106,7 +107,7 @@ def favorite(%User{} = user, id) do
{_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
{_, {:ok, %Activity{} = activity, _meta}} <-
{:common_pipeline,
- ActivityPub.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
+ Pipeline.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
{:ok, activity}
else
e ->
diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs
new file mode 100644
index 000000000..318d306af
--- /dev/null
+++ b/test/web/activity_pub/pipeline_test.exs
@@ -0,0 +1,87 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.PipelineTest do
+ use Pleroma.DataCase
+
+ import Mock
+ import Pleroma.Factory
+
+ describe "common_pipeline/2" do
+ test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
+ activity = insert(:note_activity)
+ meta = [local: true]
+
+ with_mocks([
+ {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
+ {
+ Pleroma.Web.ActivityPub.MRF,
+ [],
+ [filter: fn o -> {:ok, o} end]
+ },
+ {
+ Pleroma.Web.ActivityPub.ActivityPub,
+ [],
+ [persist: fn o, m -> {:ok, o, m} end]
+ },
+ {
+ Pleroma.Web.ActivityPub.SideEffects,
+ [],
+ [handle: fn o, m -> {:ok, o, m} end]
+ },
+ {
+ Pleroma.Web.Federator,
+ [],
+ [publish: fn _o -> :ok end]
+ }
+ ]) do
+ assert {:ok, ^activity, ^meta} =
+ Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
+
+ assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
+ assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
+ assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
+ assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
+ assert_called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do
+ activity = insert(:note_activity)
+ meta = [local: false]
+
+ with_mocks([
+ {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
+ {
+ Pleroma.Web.ActivityPub.MRF,
+ [],
+ [filter: fn o -> {:ok, o} end]
+ },
+ {
+ Pleroma.Web.ActivityPub.ActivityPub,
+ [],
+ [persist: fn o, m -> {:ok, o, m} end]
+ },
+ {
+ Pleroma.Web.ActivityPub.SideEffects,
+ [],
+ [handle: fn o, m -> {:ok, o, m} end]
+ },
+ {
+ Pleroma.Web.Federator,
+ [],
+ []
+ }
+ ]) do
+ assert {:ok, ^activity, ^meta} =
+ Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
+
+ assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
+ assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
+ assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
+ assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
+ end
+ end
+ end
+end
From 1adafa096653c4538e4162a2dffba982ee6c6d8e Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 23 Oct 2019 12:18:05 +0200
Subject: [PATCH 09/85] Credo fixes.
---
lib/pleroma/web/activity_pub/builder.ex | 4 ++--
lib/pleroma/web/activity_pub/object_validator.ex | 4 ++--
.../web/activity_pub/object_validators/like_validator.ex | 8 ++++++--
lib/pleroma/web/activity_pub/side_effects.ex | 4 ++--
test/web/activity_pub/object_validator_test.exs | 3 ++-
5 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 1787f1510..429a510b8 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -5,10 +5,10 @@ defmodule Pleroma.Web.ActivityPub.Builder do
This module encodes our addressing policies and general shape of our objects.
"""
+ alias Pleroma.Object
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
- alias Pleroma.User
- alias Pleroma.Object
@spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
def like(actor, object) do
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 33e67dbb9..27a8dd852 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -9,9 +9,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
the system.
"""
- alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
- alias Pleroma.User
alias Pleroma.Object
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
def validate(object, meta)
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
index e6a5aaca8..5fa486653 100644
--- a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
@@ -1,11 +1,15 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
use Ecto.Schema
import Ecto.Changeset
+ alias Pleroma.Object
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.User
- alias Pleroma.Object
@primary_key false
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index 6d3e77a62..666a4e310 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -5,9 +5,9 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
liked object, a `Follow` activity will add the user to the follower
collection, and so on.
"""
- alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.Object
alias Pleroma.Notification
+ alias Pleroma.Object
+ alias Pleroma.Web.ActivityPub.Utils
def handle(object, meta \\ [])
diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs
index 2292db6d7..3c5c3696e 100644
--- a/test/web/activity_pub/object_validator_test.exs
+++ b/test/web/activity_pub/object_validator_test.exs
@@ -1,10 +1,11 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
use Pleroma.DataCase
- alias Pleroma.Web.CommonAPI
alias Pleroma.Web.ActivityPub.ObjectValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.CommonAPI
+
import Pleroma.Factory
describe "likes" do
From 25077812bfc8a7a94c3fa953b2924003296470c2 Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 23 Oct 2019 12:25:20 +0200
Subject: [PATCH 10/85] SideEffectsTest: Fix test.
---
test/web/activity_pub/side_effects_test.exs | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
index 9d99e05a0..b34e45a7f 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -4,11 +4,12 @@
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
use Pleroma.DataCase
+
alias Pleroma.Object
- alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.SideEffects
+ alias Pleroma.Web.CommonAPI
import Pleroma.Factory
@@ -18,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
{:ok, post} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, like_data, _meta} = Builder.like(user, post.object)
- {:ok, like, _meta} = ActivityPub.persist(like_data, [])
+ {:ok, like, _meta} = ActivityPub.persist(like_data, [local: true])
%{like: like, user: user}
end
From 3d1b445cbf001f76af614441c241dcc299e76af7 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 5 Nov 2019 15:02:09 +0100
Subject: [PATCH 11/85] Object Validators: Extract common validations.
---
.../web/activity_pub/object_validator.ex | 7 ++--
.../object_validators/common_validations.ex | 32 +++++++++++++++++++
.../object_validators/like_validator.ex | 26 +++------------
.../web/activity_pub/transmogrifier.ex | 7 ++--
test/web/activity_pub/side_effects_test.exs | 2 +-
5 files changed, 47 insertions(+), 27 deletions(-)
create mode 100644 lib/pleroma/web/activity_pub/object_validators/common_validations.ex
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 27a8dd852..539be1143 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -17,9 +17,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
def validate(object, meta)
def validate(%{"type" => "Like"} = object, meta) do
- with {_, %{valid?: true, changes: object}} <-
- {:validate_object, LikeValidator.cast_and_validate(object)} do
- object = stringify_keys(object)
+ with {_, {:ok, object}} <-
+ {:validate_object,
+ object |> LikeValidator.cast_and_validate() |> Ecto.Changeset.apply_action(:insert)} do
+ object = stringify_keys(object |> Map.from_struct())
{:ok, object, meta}
else
e -> {:error, e}
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
new file mode 100644
index 000000000..db0e2072d
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.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.ActivityPub.ObjectValidators.CommonValidations do
+ import Ecto.Changeset
+
+ alias Pleroma.Object
+ alias Pleroma.User
+
+ def validate_actor_presence(cng, field_name \\ :actor) do
+ cng
+ |> validate_change(field_name, fn field_name, actor ->
+ if User.get_cached_by_ap_id(actor) do
+ []
+ else
+ [{field_name, "can't find user"}]
+ end
+ end)
+ end
+
+ def validate_object_presence(cng, field_name \\ :object) do
+ cng
+ |> validate_change(field_name, fn field_name, actor ->
+ if Object.get_cached_by_ap_id(actor) do
+ []
+ else
+ [{field_name, "can't find user"}]
+ end
+ end)
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
index 5fa486653..ccbc7d071 100644
--- a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
@@ -4,13 +4,13 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
use Ecto.Schema
- import Ecto.Changeset
- alias Pleroma.Object
- alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
alias Pleroma.Web.ActivityPub.Utils
+ import Ecto.Changeset
+ import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
+
@primary_key false
embedded_schema do
@@ -38,8 +38,8 @@ def validate_data(data_cng) do
data_cng
|> validate_inclusion(:type, ["Like"])
|> validate_required([:id, :type, :object, :actor, :context, :to, :cc])
- |> validate_change(:actor, &actor_valid?/2)
- |> validate_change(:object, &object_valid?/2)
+ |> validate_actor_presence()
+ |> validate_object_presence()
|> validate_existing_like()
end
@@ -54,20 +54,4 @@ def validate_existing_like(%{changes: %{actor: actor, object: object}} = cng) do
end
def validate_existing_like(cng), do: cng
-
- def actor_valid?(field_name, actor) do
- if User.get_cached_by_ap_id(actor) do
- []
- else
- [{field_name, "can't find user"}]
- end
- end
-
- def object_valid?(field_name, object) do
- if Object.get_cached_by_ap_id(object) do
- []
- else
- [{field_name, "can't find object"}]
- end
- end
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 4dd884ce9..9a0c37e13 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -566,8 +566,11 @@ def handle_incoming(
end
def handle_incoming(%{"type" => "Like"} = data, _options) do
- with {_, %{changes: cast_data}} <- {:casting_data, LikeValidator.cast_data(data)},
- cast_data <- ObjectValidator.stringify_keys(cast_data),
+ with {_, {:ok, cast_data_sym}} <-
+ {:casting_data,
+ data |> LikeValidator.cast_data() |> Ecto.Changeset.apply_action(:insert)},
+ {_, cast_data} <-
+ {:stringify_keys, ObjectValidator.stringify_keys(cast_data_sym |> Map.from_struct())},
:ok <- ObjectValidator.fetch_actor_and_object(cast_data),
{_, {:ok, cast_data}} <- {:maybe_add_context, maybe_add_context_from_object(cast_data)},
{_, {:ok, cast_data}} <-
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
index b34e45a7f..ef91954ae 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
{:ok, post} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, like_data, _meta} = Builder.like(user, post.object)
- {:ok, like, _meta} = ActivityPub.persist(like_data, [local: true])
+ {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
%{like: like, user: user}
end
From faced6236b9e2ce9675cf743068f16098b744562 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 5 Nov 2019 15:02:31 +0100
Subject: [PATCH 12/85] NoteValidator: Add very basic validator for Note
objects.
---
.../object_validators/note_validator.ex | 64 +++++++++++++++++++
.../object_validators/note_validator_test.exs | 35 ++++++++++
2 files changed, 99 insertions(+)
create mode 100644 lib/pleroma/web/activity_pub/object_validators/note_validator.ex
create mode 100644 test/web/activity_pub/object_validators/note_validator_test.exs
diff --git a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
new file mode 100644
index 000000000..c660f30f0
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
@@ -0,0 +1,64 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
+ use Ecto.Schema
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+
+ import Ecto.Changeset
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, :string, primary_key: true)
+ field(:to, {:array, :string}, default: [])
+ field(:cc, {:array, :string}, default: [])
+ field(:bto, {:array, :string}, default: [])
+ field(:bcc, {:array, :string}, default: [])
+ # TODO: Write type
+ field(:tag, {:array, :map}, default: [])
+ field(:type, :string)
+ field(:content, :string)
+ field(:context, :string)
+ field(:actor, Types.ObjectID)
+ field(:attributedTo, Types.ObjectID)
+ field(:summary, :string)
+ # TODO: Write type
+ field(:published, :string)
+ # TODO: Write type
+ field(:emoji, :map, default: %{})
+ field(:sensitive, :boolean, default: false)
+ # TODO: Write type
+ field(:attachment, {:array, :map}, default: [])
+ field(:replies_count, :integer, default: 0)
+ field(:like_count, :integer, default: 0)
+ field(:announcement_count, :integer, default: 0)
+ field(:inRepyTo, :string)
+
+ field(:likes, {:array, :string}, default: [])
+ field(:announcements, {:array, :string}, default: [])
+
+ # see if needed
+ field(:conversation, :string)
+ field(:context_id, :string)
+ end
+
+ def cast_and_validate(data) do
+ data
+ |> cast_data()
+ |> validate_data()
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> cast(data, __schema__(:fields))
+ end
+
+ def validate_data(data_cng) do
+ data_cng
+ |> validate_inclusion(:type, ["Note"])
+ |> validate_required([:id, :actor, :to, :cc, :type, :content, :context])
+ end
+end
diff --git a/test/web/activity_pub/object_validators/note_validator_test.exs b/test/web/activity_pub/object_validators/note_validator_test.exs
new file mode 100644
index 000000000..2bcd75e25
--- /dev/null
+++ b/test/web/activity_pub/object_validators/note_validator_test.exs
@@ -0,0 +1,35 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
+ alias Pleroma.Web.ActivityPub.Utils
+
+ import Pleroma.Factory
+
+ describe "Notes" do
+ setup do
+ user = insert(:user)
+
+ note = %{
+ "id" => Utils.generate_activity_id(),
+ "type" => "Note",
+ "actor" => user.ap_id,
+ "to" => [user.follower_address],
+ "cc" => [],
+ "content" => "Hellow this is content.",
+ "context" => "xxx",
+ "summary" => "a post"
+ }
+
+ %{user: user, note: note}
+ end
+
+ test "a basic note validates", %{note: note} do
+ %{valid?: true} = NoteValidator.cast_and_validate(note)
+ end
+ end
+end
From 1993d7096d673d8a8151fedd7bcac909d584d13d Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 5 Dec 2019 12:33:06 +0100
Subject: [PATCH 13/85] Validators: Add a type for the datetime used in AP.
---
.../object_validators/note_validator.ex | 3 +-
.../object_validators/types/date_time.ex | 34 +++++++++++++++++++
.../types/date_time_test.exs | 32 +++++++++++++++++
3 files changed, 67 insertions(+), 2 deletions(-)
create mode 100644 lib/pleroma/web/activity_pub/object_validators/types/date_time.ex
create mode 100644 test/web/activity_pub/object_validators/types/date_time_test.exs
diff --git a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
index c660f30f0..eea15ce1c 100644
--- a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
@@ -25,8 +25,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
field(:actor, Types.ObjectID)
field(:attributedTo, Types.ObjectID)
field(:summary, :string)
- # TODO: Write type
- field(:published, :string)
+ field(:published, Types.DateTime)
# TODO: Write type
field(:emoji, :map, default: %{})
field(:sensitive, :boolean, default: false)
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/date_time.ex b/lib/pleroma/web/activity_pub/object_validators/types/date_time.ex
new file mode 100644
index 000000000..4f412fcde
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/types/date_time.ex
@@ -0,0 +1,34 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTime do
+ @moduledoc """
+ The AP standard defines the date fields in AP as xsd:DateTime. Elixir's
+ DateTime can't parse this, but it can parse the related iso8601. This
+ module punches the date until it looks like iso8601 and normalizes to
+ it.
+
+ DateTimes without a timezone offset are treated as UTC.
+
+ Reference: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-published
+ """
+ use Ecto.Type
+
+ def type, do: :string
+
+ def cast(datetime) when is_binary(datetime) do
+ with {:ok, datetime, _} <- DateTime.from_iso8601(datetime) do
+ {:ok, DateTime.to_iso8601(datetime)}
+ else
+ {:error, :missing_offset} -> cast("#{datetime}Z")
+ _e -> :error
+ end
+ end
+
+ def cast(_), do: :error
+
+ def dump(data) do
+ {:ok, data}
+ end
+
+ def load(data) do
+ {:ok, data}
+ end
+end
diff --git a/test/web/activity_pub/object_validators/types/date_time_test.exs b/test/web/activity_pub/object_validators/types/date_time_test.exs
new file mode 100644
index 000000000..3e17a9497
--- /dev/null
+++ b/test/web/activity_pub/object_validators/types/date_time_test.exs
@@ -0,0 +1,32 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTimeTest do
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTime
+ use Pleroma.DataCase
+
+ test "it validates an xsd:Datetime" do
+ valid_strings = [
+ "2004-04-12T13:20:00",
+ "2004-04-12T13:20:15.5",
+ "2004-04-12T13:20:00-05:00",
+ "2004-04-12T13:20:00Z"
+ ]
+
+ invalid_strings = [
+ "2004-04-12T13:00",
+ "2004-04-1213:20:00",
+ "99-04-12T13:00",
+ "2004-04-12"
+ ]
+
+ assert {:ok, "2004-04-01T12:00:00Z"} == DateTime.cast("2004-04-01T12:00:00Z")
+
+ Enum.each(valid_strings, fn date_time ->
+ result = DateTime.cast(date_time)
+ assert {:ok, _} = result
+ end)
+
+ Enum.each(invalid_strings, fn date_time ->
+ result = DateTime.cast(date_time)
+ assert :error == result
+ end)
+ end
+end
From d4bafabfd14887e61eb5bc1d877035dcfebbd33f Mon Sep 17 00:00:00 2001
From: lain
Date: Mon, 9 Dec 2019 10:39:14 +0100
Subject: [PATCH 14/85] Beginnings of the create validator
---
.../object_validators/create_validator.ex | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 lib/pleroma/web/activity_pub/object_validators/create_validator.ex
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
new file mode 100644
index 000000000..bd90f7250
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
@@ -0,0 +1,31 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
+ use Ecto.Schema
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+ alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
+
+ import Ecto.Changeset
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, :string, primary_key: true)
+ field(:actor, Types.ObjectID)
+ field(:type, :string)
+ field(:to, {:array, :string})
+ field(:cc, {:array, :string})
+ field(:bto, {:array, :string}, default: [])
+ field(:bcc, {:array, :string}, default: [])
+
+ embeds_one(:object, NoteValidator)
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> cast(data, __schema__(:fields))
+ end
+end
From d3cf7e19fbe089b3a6d62d6a26f3dfc866a6669d Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Tue, 17 Mar 2020 13:02:10 +0100
Subject: [PATCH 15/85] activity_pub_controller_test.exs: test posting with AP
C2S uploaded media
---
.../activity_pub_controller_test.exs | 34 +++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs
index bd8e0b5cc..2bd494a37 100644
--- a/test/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/web/activity_pub/activity_pub_controller_test.exs
@@ -1241,16 +1241,46 @@ test "POST /api/ap/upload_media", %{conn: conn} do
filename: "an_image.jpg"
}
- conn =
+ object =
conn
|> assign(:user, user)
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
+ |> json_response(:created)
- assert object = json_response(conn, :created)
assert object["name"] == desc
assert object["type"] == "Document"
assert object["actor"] == user.ap_id
+ assert [%{"href" => object_href}] = object["url"]
+ activity_request = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "type" => "Create",
+ "object" => %{
+ "type" => "Note",
+ "content" => "AP C2S test, attachment",
+ "attachment" => [object]
+ },
+ "to" => "https://www.w3.org/ns/activitystreams#Public",
+ "cc" => []
+ }
+
+ activity_response =
+ conn
+ |> assign(:user, user)
+ |> post("/users/#{user.nickname}/outbox", activity_request)
+ |> json_response(:created)
+
+ assert activity_response["id"]
+ assert activity_response["object"]
+ assert activity_response["actor"] == user.ap_id
+
+ assert %Object{data: %{"attachment" => [attachment]}} = Object.normalize(activity_response["object"])
+ assert attachment["type"] == "Document"
+ assert attachment["name"] == desc
+ assert [%{"href" => attachment_href}] = attachment["url"]
+ assert attachment_href == object_href
+
+ # Fails if unauthenticated
conn
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|> json_response(403)
From f9d622d25a744f58fbaf8370ad4435597bb15bf0 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Thu, 19 Mar 2020 15:08:49 +0100
Subject: [PATCH 16/85] WIP
---
lib/pleroma/web/activity_pub/transmogrifier.ex | 15 ---------------
.../activity_pub_controller_test.exs | 18 ++++++++++++++----
2 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 9cd3de705..db848f657 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -202,21 +202,6 @@ def fix_context(object) do
|> Map.put("conversation", context)
end
- def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
- attachments =
- 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
- |> Map.put("mediaType", media_type)
- |> Map.put("url", url)
- end)
-
- Map.put(object, "attachment", attachments)
- end
-
def fix_attachments(%{"attachment" => attachment} = object) when is_map(attachment) do
object
|> Map.put("attachment", [attachment])
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs
index 2bd494a37..01c955c0a 100644
--- a/test/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/web/activity_pub/activity_pub_controller_test.exs
@@ -1250,7 +1250,9 @@ test "POST /api/ap/upload_media", %{conn: conn} do
assert object["name"] == desc
assert object["type"] == "Document"
assert object["actor"] == user.ap_id
- assert [%{"href" => object_href}] = object["url"]
+ assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"]
+ assert is_binary(object_href)
+ assert object_mediatype == "image/jpeg"
activity_request = %{
"@context" => "https://www.w3.org/ns/activitystreams",
@@ -1274,11 +1276,19 @@ test "POST /api/ap/upload_media", %{conn: conn} do
assert activity_response["object"]
assert activity_response["actor"] == user.ap_id
- assert %Object{data: %{"attachment" => [attachment]}} = Object.normalize(activity_response["object"])
+ assert %Object{data: %{"attachment" => [attachment]}} =
+ Object.normalize(activity_response["object"])
+
assert attachment["type"] == "Document"
assert attachment["name"] == desc
- assert [%{"href" => attachment_href}] = attachment["url"]
- assert attachment_href == object_href
+
+ assert [
+ %{
+ "href" => ^object_href,
+ "type" => "Link",
+ "mediaType" => ^object_mediatype
+ }
+ ] = attachment["url"]
# Fails if unauthenticated
conn
From 7d275970ab191af539acbc0baec3bc1d0a2558e1 Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Thu, 19 Mar 2020 10:08:11 -0500
Subject: [PATCH 17/85] Add emoji reactions to features in nodeinfo
---
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index 18eb41333..c653a80c3 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -74,7 +74,8 @@ def raw_nodeinfo do
end,
if Config.get([:instance, :safe_dm_mentions]) do
"safe_dm_mentions"
- end
+ end,
+ "pleroma_emoji_reactions"
]
|> Enum.filter(& &1)
From 9b9d67bbec537df6f7c5729e81da6deeaf896bd9 Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 19 Mar 2020 18:16:12 +0100
Subject: [PATCH 18/85] Fix linting.
---
.../web/activity_pub/object_validators/create_validator.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
index bd90f7250..9e480c4ed 100644
--- a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
@@ -5,8 +5,8 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
use Ecto.Schema
- alias Pleroma.Web.ActivityPub.ObjectValidators.Types
alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
import Ecto.Changeset
From c1fd4f665335ba67336bd1b2fab2d9df5e247e08 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Thu, 19 Mar 2020 19:10:03 +0100
Subject: [PATCH 19/85] transmogrifier.ex: rework fix_attachment for better IR
---
.../web/activity_pub/transmogrifier.ex | 45 +++++++++++++++++++
test/web/activity_pub/transmogrifier_test.exs | 30 +++----------
2 files changed, 50 insertions(+), 25 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index db848f657..df5ca0239 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -202,6 +202,51 @@ def fix_context(object) do
|> Map.put("conversation", context)
end
+ defp add_if_present(map, _key, nil), do: map
+
+ defp add_if_present(map, key, value) do
+ Map.put(map, key, value)
+ end
+
+ def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
+ attachments =
+ Enum.map(attachment, fn data ->
+ url =
+ cond do
+ is_list(data["url"]) -> List.first(data["url"])
+ is_map(data["url"]) -> data["url"]
+ true -> nil
+ end
+
+ media_type =
+ cond do
+ is_map(url) && is_binary(url["mediaType"]) -> url["mediaType"]
+ is_binary(data["mediaType"]) -> data["mediaType"]
+ is_binary(data["mimeType"]) -> data["mimeType"]
+ true -> nil
+ end
+
+ href =
+ cond do
+ is_map(url) && is_binary(url["href"]) -> url["href"]
+ is_binary(data["url"]) -> data["url"]
+ is_binary(data["href"]) -> data["href"]
+ end
+
+ attachment_url =
+ %{"href" => href}
+ |> add_if_present("mediaType", media_type)
+ |> add_if_present("type", Map.get(url || %{}, "type"))
+
+ %{"url" => [attachment_url]}
+ |> add_if_present("mediaType", media_type)
+ |> add_if_present("type", data["type"])
+ |> add_if_present("name", data["name"])
+ end)
+
+ Map.put(object, "attachment", attachments)
+ end
+
def fix_attachments(%{"attachment" => attachment} = object) when is_map(attachment) do
object
|> Map.put("attachment", [attachment])
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index efbca82f6..242d933e7 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -1228,19 +1228,13 @@ test "it remaps video URLs as attachments if necessary" do
attachment = %{
"type" => "Link",
"mediaType" => "video/mp4",
- "href" =>
- "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
- "mimeType" => "video/mp4",
- "size" => 5_015_880,
"url" => [
%{
"href" =>
"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
- "mediaType" => "video/mp4",
- "type" => "Link"
+ "mediaType" => "video/mp4"
}
- ],
- "width" => 480
+ ]
}
assert object.data["url"] ==
@@ -2067,11 +2061,7 @@ test "returns modified object when attachment is map" do
%{
"mediaType" => "video/mp4",
"url" => [
- %{
- "href" => "https://peertube.moe/stat-480.mp4",
- "mediaType" => "video/mp4",
- "type" => "Link"
- }
+ %{"href" => "https://peertube.moe/stat-480.mp4", "mediaType" => "video/mp4"}
]
}
]
@@ -2089,23 +2079,13 @@ test "returns modified object when attachment is list" do
%{
"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"}
]
},
%{
- "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"
- }
+ %{"href" => "https://pe.er/stat-480.mp4", "mediaType" => "video/mp4"}
]
}
]
From 6c1232b486dcad5a644b4292697d08ebe3000cb3 Mon Sep 17 00:00:00 2001
From: lain
Date: Fri, 20 Mar 2020 15:00:28 +0100
Subject: [PATCH 20/85] NotificationController: Fix test.
---
.../mastodon_api/controllers/notification_controller_test.exs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs
index e407b8297..adbb78da6 100644
--- a/test/web/mastodon_api/controllers/notification_controller_test.exs
+++ b/test/web/mastodon_api/controllers/notification_controller_test.exs
@@ -310,7 +310,7 @@ test "filters notifications using include_types" do
{: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, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
{:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
From 4a2538967caf5b0f9970cc5f973c16ea5d776aa3 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 24 Mar 2020 20:18:27 +0400
Subject: [PATCH 21/85] Support pagination in conversations
---
CHANGELOG.md | 3 +++
lib/pleroma/web/activity_pub/activity_pub.ex | 2 +-
.../controllers/pleroma_api_controller.ex | 10 +++++-----
.../controllers/pleroma_api_controller_test.exs | 17 +++++++++++++++++
4 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15a073c64..905364d7e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
+### Fixed
+- Support pagination in conversations API
+
## [2.0.0] - 2019-03-08
### Security
- Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request.
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 30e282840..351d1bdb8 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -696,7 +696,7 @@ def move(%User{} = origin, %User{} = target, local \\ true) do
end
end
- defp fetch_activities_for_context_query(context, opts) do
+ def fetch_activities_for_context_query(context, opts) do
public = [Constants.as_public()]
recipients =
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 dae7f0f2f..edb071baa 100644
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
@@ -110,12 +110,11 @@ def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id})
end
def conversation_statuses(
- %{assigns: %{user: user}} = conn,
+ %{assigns: %{user: %{id: user_id} = user}} = conn,
%{"id" => participation_id} = params
) do
- with %Participation{} = participation <-
- Participation.get(participation_id, preload: [:conversation]),
- true <- user.id == participation.user_id do
+ with %Participation{user_id: ^user_id} = participation <-
+ Participation.get(participation_id, preload: [:conversation]) do
params =
params
|> Map.put("blocking_user", user)
@@ -124,7 +123,8 @@ def conversation_statuses(
activities =
participation.conversation.ap_id
- |> ActivityPub.fetch_activities_for_context(params)
+ |> ActivityPub.fetch_activities_for_context_query(params)
+ |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
|> Enum.reverse()
conn
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 32250f06f..8bf7eb3be 100644
--- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs
+++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs
@@ -169,6 +169,23 @@ test "/api/v1/pleroma/conversations/:id/statuses" do
id_one = activity.id
id_two = activity_two.id
assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result
+
+ {:ok, %{id: id_three}} =
+ CommonAPI.post(other_user, %{
+ "status" => "Bye!",
+ "in_reply_to_status_id" => activity.id,
+ "in_reply_to_conversation_id" => participation.id
+ })
+
+ assert [%{"id" => ^id_two}, %{"id" => ^id_three}] =
+ conn
+ |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?limit=2")
+ |> json_response(:ok)
+
+ assert [%{"id" => ^id_three}] =
+ conn
+ |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?min_id=#{id_two}")
+ |> json_response(:ok)
end
test "PATCH /api/v1/pleroma/conversations/:id" do
From 74560e888e5e3e4dc2fa5b4fec4cf3986a1d1a55 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 24 Mar 2020 18:20:58 +0000
Subject: [PATCH 22/85] Apply suggestion to
lib/pleroma/web/activity_pub/object_validators/create_validator.ex
---
.../web/activity_pub/object_validators/create_validator.ex | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
index 9e480c4ed..872a12c48 100644
--- a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
@@ -25,7 +25,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
end
def cast_data(data) do
- %__MODULE__{}
- |> cast(data, __schema__(:fields))
+ cast(%__MODULE__{}, data, __schema__(:fields))
end
end
From aaf00f1ff59fc279758f5fa5ceaf758d683bd216 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 24 Mar 2020 18:24:09 +0000
Subject: [PATCH 23/85] Apply suggestion to
lib/pleroma/web/activity_pub/pipeline.ex
---
lib/pleroma/web/activity_pub/pipeline.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
index cb3571917..25f29bf63 100644
--- a/lib/pleroma/web/activity_pub/pipeline.ex
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -35,7 +35,7 @@ defp maybe_federate(activity, meta) do
{:ok, :not_federated}
end
else
- _e -> {:error, "local not set in meta"}
+ _e -> {:error, :badarg}
end
end
end
From f31688246470273cc35588d0f1c2187edc6084c7 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 24 Mar 2020 18:37:53 +0000
Subject: [PATCH 24/85] Apply suggestion to
lib/pleroma/web/activity_pub/activity_pub.ex
---
lib/pleroma/web/activity_pub/activity_pub.ex | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index d9f30e629..dd4b04185 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -150,7 +150,6 @@ def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when
{_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map),
{recipients, _, _} = get_recipients(map),
- # ???
{:fake, false, map, recipients} <- {:fake, fake, map, recipients},
{:containment, :ok} <- {:containment, Containment.contain_child(map)},
{:ok, map, object} <- insert_full_object(map) do
From 64165d1df95bc3a22260dafa4584471427685864 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Tue, 24 Mar 2020 20:21:27 +0100
Subject: [PATCH 25/85] node_info_test.exs: Add test on the default feature
list
---
test/web/node_info_test.exs | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs
index ee10ad5db..e8922a8ee 100644
--- a/test/web/node_info_test.exs
+++ b/test/web/node_info_test.exs
@@ -128,6 +128,27 @@ test "it shows if federation is enabled/disabled", %{conn: conn} do
end
end
+ test "it shows default features flags", %{conn: conn} do
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["features"] --
+ [
+ "pleroma_api",
+ "mastodon_api",
+ "mastodon_api_streaming",
+ "polls",
+ "pleroma_explicit_addressing",
+ "shareable_emoji_packs",
+ "multifetch",
+ "chat",
+ "relay",
+ "pleroma_emoji_reactions"
+ ] == []
+ end
+
test "it shows MRF transparency data if enabled", %{conn: conn} do
config = Pleroma.Config.get([:instance, :rewrite_policy])
Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
From 03a18cf037d7a9b4ba84ff456b434d65e3290965 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Tue, 24 Mar 2020 20:39:19 +0100
Subject: [PATCH 26/85] node_info_test: Bump default features list
---
test/web/node_info_test.exs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs
index 01a67afd7..e5eebced1 100644
--- a/test/web/node_info_test.exs
+++ b/test/web/node_info_test.exs
@@ -145,7 +145,8 @@ test "it shows default features flags", %{conn: conn} do
"multifetch",
"chat",
"relay",
- "pleroma_emoji_reactions"
+ "pleroma_emoji_reactions",
+ "pleroma:api/v1/notifications:include_types_filter"
] == []
end
From 4cf1007a7d478a54a759d018dd7ce958a45f3977 Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 26 Mar 2020 15:16:54 +0100
Subject: [PATCH 27/85] ActivityPub: Small refactor.
---
lib/pleroma/web/activity_pub/activity_pub.ex | 23 ++++++++++----------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index dd4b04185..35c2eb133 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -129,18 +129,17 @@ def increase_poll_votes_if_vote(_create_data), do: :noop
# TODO rewrite in with style
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
def persist(object, meta) do
- local = Keyword.fetch!(meta, :local)
- {recipients, _, _} = get_recipients(object)
-
- {:ok, activity} =
- Repo.insert(%Activity{
- data: object,
- local: local,
- recipients: recipients,
- actor: object["actor"]
- })
-
- {:ok, activity, meta}
+ with local <- Keyword.fetch!(meta, :local),
+ {recipients, _, _} <- get_recipients(object),
+ {:ok, activity} <-
+ Repo.insert(%Activity{
+ data: object,
+ local: local,
+ recipients: recipients,
+ actor: object["actor"]
+ }) do
+ {:ok, activity, meta}
+ end
end
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
From d7aa0b645b0da48af830f252ae80458afc965281 Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 26 Mar 2020 14:23:19 +0000
Subject: [PATCH 28/85] Apply suggestion to
lib/pleroma/web/activity_pub/object_validator.ex
---
lib/pleroma/web/activity_pub/object_validator.ex | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index cff924047..9b2889e92 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -26,8 +26,7 @@ def validate(%{"type" => "Like"} = object, meta) do
def stringify_keys(object) do
object
- |> Enum.map(fn {key, val} -> {to_string(key), val} end)
- |> Enum.into(%{})
+ |> Map.new(fn {key, val} -> {to_string(key), val} end)
end
def fetch_actor_and_object(object) do
From eaacc648392e6544cd3a3b77bde266e34cebf634 Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 26 Mar 2020 15:33:10 +0100
Subject: [PATCH 29/85] Refactors.
---
lib/pleroma/web/activity_pub/activity_pub.ex | 3 +--
.../activity_pub/object_validators/common_validations.ex | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 35c2eb133..55f4de693 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -125,8 +125,6 @@ def increase_poll_votes_if_vote(%{
def increase_poll_votes_if_vote(_create_data), do: :noop
- @spec insert(map(), boolean(), boolean(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
- # TODO rewrite in with style
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
def persist(object, meta) do
with local <- Keyword.fetch!(meta, :local),
@@ -142,6 +140,7 @@ def persist(object, meta) do
end
end
+ @spec insert(map(), boolean(), boolean(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
with nil <- Activity.normalize(map),
map <- lazy_put_activity_defaults(map, fake),
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
index db0e2072d..26a57f02b 100644
--- a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
@@ -21,11 +21,11 @@ def validate_actor_presence(cng, field_name \\ :actor) do
def validate_object_presence(cng, field_name \\ :object) do
cng
- |> validate_change(field_name, fn field_name, actor ->
- if Object.get_cached_by_ap_id(actor) do
+ |> validate_change(field_name, fn field_name, object ->
+ if Object.get_cached_by_ap_id(object) do
[]
else
- [{field_name, "can't find user"}]
+ [{field_name, "can't find object"}]
end
end)
end
From 0adaab8e753b0ec22feccfc03d301073327a6d31 Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 26 Mar 2020 15:37:42 +0100
Subject: [PATCH 30/85] Bump copyright dates.
---
COPYING | 4 ++--
lib/pleroma/web/activity_pub/object_validator.ex | 2 +-
.../web/activity_pub/object_validators/common_validations.ex | 2 +-
.../web/activity_pub/object_validators/create_validator.ex | 2 +-
.../web/activity_pub/object_validators/like_validator.ex | 2 +-
.../web/activity_pub/object_validators/note_validator.ex | 2 +-
lib/pleroma/web/activity_pub/pipeline.ex | 2 +-
priv/repo/migrations/20190408123347_create_conversations.exs | 2 +-
.../activity_pub/object_validators/note_validator_test.exs | 2 +-
test/web/activity_pub/pipeline_test.exs | 2 +-
test/web/activity_pub/side_effects_test.exs | 2 +-
11 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/COPYING b/COPYING
index 0aede0fba..3140c8038 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Unless otherwise stated this repository is copyright © 2017-2019
+Unless otherwise stated this repository is copyright © 2017-2020
Pleroma Authors , and is distributed under
The GNU Affero General Public License Version 3, you should have received a
copy of the license file as AGPL-3.
@@ -23,7 +23,7 @@ priv/static/images/pleroma-fox-tan-shy.png
---
-The following files are copyright © 2017-2019 Pleroma Authors
+The following files are copyright © 2017-2020 Pleroma Authors
, and are distributed under the Creative Commons
Attribution-ShareAlike 4.0 International license, you should have received
a copy of the license file as CC-BY-SA-4.0.
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 9b2889e92..dc4bce059 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidator do
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
index 26a57f02b..b479c3918 100644
--- a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
index 872a12c48..908381981 100644
--- a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
index ccbc7d071..2c1d38b06 100644
--- a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
diff --git a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
index eea15ce1c..fc65f1b7c 100644
--- a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
index 25f29bf63..eed53cd34 100644
--- a/lib/pleroma/web/activity_pub/pipeline.ex
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Pipeline do
diff --git a/priv/repo/migrations/20190408123347_create_conversations.exs b/priv/repo/migrations/20190408123347_create_conversations.exs
index d75459e82..3eaa6136c 100644
--- a/priv/repo/migrations/20190408123347_create_conversations.exs
+++ b/priv/repo/migrations/20190408123347_create_conversations.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.CreateConversations do
diff --git a/test/web/activity_pub/object_validators/note_validator_test.exs b/test/web/activity_pub/object_validators/note_validator_test.exs
index 2bcd75e25..30c481ffb 100644
--- a/test/web/activity_pub/object_validators/note_validator_test.exs
+++ b/test/web/activity_pub/object_validators/note_validator_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do
diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs
index 318d306af..f3c437498 100644
--- a/test/web/activity_pub/pipeline_test.exs
+++ b/test/web/activity_pub/pipeline_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.PipelineTest do
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
index ef91954ae..b67bd14b3 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
From 0c60c0a76a2fcc8d13992b51704c21a35da10a0b Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 26 Mar 2020 15:44:14 +0100
Subject: [PATCH 31/85] Validators: Use correct type for IDs.
---
.../web/activity_pub/object_validators/create_validator.ex | 2 +-
.../web/activity_pub/object_validators/like_validator.ex | 2 +-
.../web/activity_pub/object_validators/note_validator.ex | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
index 908381981..926804ce7 100644
--- a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
@primary_key false
embedded_schema do
- field(:id, :string, primary_key: true)
+ field(:id, Types.ObjectID, primary_key: true)
field(:actor, Types.ObjectID)
field(:type, :string)
field(:to, {:array, :string})
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
index 2c1d38b06..49546ceaa 100644
--- a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
@primary_key false
embedded_schema do
- field(:id, :string, primary_key: true)
+ field(:id, Types.ObjectID, primary_key: true)
field(:type, :string)
field(:object, Types.ObjectID)
field(:actor, Types.ObjectID)
diff --git a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
index fc65f1b7c..c95b622e4 100644
--- a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
@primary_key false
embedded_schema do
- field(:id, :string, primary_key: true)
+ field(:id, Types.ObjectID, primary_key: true)
field(:to, {:array, :string}, default: [])
field(:cc, {:array, :string}, default: [])
field(:bto, {:array, :string}, default: [])
From 69fc1dd69ff9d63af1785bb0701576cb5cde51f2 Mon Sep 17 00:00:00 2001
From: lain
Date: Thu, 26 Mar 2020 14:45:28 +0000
Subject: [PATCH 32/85] Apply suggestion to
lib/pleroma/web/activity_pub/pipeline.ex
---
lib/pleroma/web/activity_pub/pipeline.ex | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
index 25f29bf63..0068d60be 100644
--- a/lib/pleroma/web/activity_pub/pipeline.ex
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -22,6 +22,7 @@ def common_pipeline(object, meta) do
{_, {:ok, _}} <- {:federation, maybe_federate(activity, meta)} do
{:ok, activity, meta}
else
+ {:mrf_object, {:reject, _}} -> {:ok, nil, meta}
e -> {:error, e}
end
end
From be9d18461a5ed6bd835e2eba8d3b54ba61fc51fb Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Sat, 28 Mar 2020 18:49:03 +0300
Subject: [PATCH 33/85] FollowingRelationship storage & performance
optimizations (state turned `ecto_enum`-driven integer, reorganized indices
etc.).
---
lib/pleroma/ecto_enums.ex | 6 +++
lib/pleroma/following_relationship.ex | 43 ++++++++++++++++---
lib/pleroma/user.ex | 18 +++++---
lib/pleroma/user/query.ex | 6 +--
lib/pleroma/web/activity_pub/mrf.ex | 2 +-
.../web/activity_pub/transmogrifier.ex | 13 +++---
lib/pleroma/web/common_api/common_api.ex | 4 +-
.../web/mastodon_api/views/account_view.ex | 6 +--
...llowing_relationships_state_to_integer.exs | 29 +++++++++++++
...owing_relationships_following_id_index.exs | 11 +++++
test/following_relationship_test.exs | 8 ++--
test/tasks/user_test.exs | 2 +-
test/user_test.exs | 9 ++--
test/web/activity_pub/transmogrifier_test.exs | 2 +-
test/web/common_api/common_api_test.exs | 4 +-
.../follow_request_controller_test.exs | 4 +-
test/web/streamer/streamer_test.exs | 6 +--
17 files changed, 128 insertions(+), 45 deletions(-)
create mode 100644 priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs
create mode 100644 priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs
diff --git a/lib/pleroma/ecto_enums.ex b/lib/pleroma/ecto_enums.ex
index d9b601223..b98ac4ba1 100644
--- a/lib/pleroma/ecto_enums.ex
+++ b/lib/pleroma/ecto_enums.ex
@@ -11,3 +11,9 @@
notification_mute: 4,
inverse_subscription: 5
)
+
+defenum(FollowingRelationshipStateEnum,
+ follow_pending: 1,
+ follow_accept: 2,
+ follow_reject: 3
+)
diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex
index a9538ea4e..a28da8bec 100644
--- a/lib/pleroma/following_relationship.ex
+++ b/lib/pleroma/following_relationship.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.FollowingRelationship do
alias Pleroma.User
schema "following_relationships" do
- field(:state, :string, default: "accept")
+ field(:state, FollowingRelationshipStateEnum, default: :follow_pending)
belongs_to(:follower, User, type: CompatType)
belongs_to(:following, User, type: CompatType)
@@ -27,6 +27,19 @@ def changeset(%__MODULE__{} = following_relationship, attrs) do
|> put_assoc(:follower, attrs.follower)
|> put_assoc(:following, attrs.following)
|> validate_required([:state, :follower, :following])
+ |> unique_constraint(:follower_id,
+ name: :following_relationships_follower_id_following_id_index
+ )
+ |> validate_not_self_relationship()
+ end
+
+ def state_to_enum(state) when is_binary(state) do
+ case state do
+ "pending" -> :follow_pending
+ "accept" -> :follow_accept
+ "reject" -> :follow_reject
+ _ -> raise "State is not convertible to FollowingRelationshipStateEnum: #{state}"
+ end
end
def get(%User{} = follower, %User{} = following) do
@@ -35,7 +48,7 @@ def get(%User{} = follower, %User{} = following) do
|> Repo.one()
end
- def update(follower, following, "reject"), do: unfollow(follower, following)
+ def update(follower, following, :follow_reject), do: unfollow(follower, following)
def update(%User{} = follower, %User{} = following, state) do
case get(follower, following) do
@@ -50,7 +63,7 @@ def update(%User{} = follower, %User{} = following, state) do
end
end
- def follow(%User{} = follower, %User{} = following, state \\ "accept") do
+ def follow(%User{} = follower, %User{} = following, state \\ :follow_accept) do
%__MODULE__{}
|> changeset(%{follower: follower, following: following, state: state})
|> Repo.insert(on_conflict: :nothing)
@@ -80,7 +93,7 @@ def following_count(%User{} = user) do
def get_follow_requests(%User{id: id}) do
__MODULE__
|> join(:inner, [r], f in assoc(r, :follower))
- |> where([r], r.state == "pending")
+ |> where([r], r.state == ^:follow_pending)
|> where([r], r.following_id == ^id)
|> select([r, f], f)
|> Repo.all()
@@ -88,7 +101,7 @@ def get_follow_requests(%User{id: id}) do
def following?(%User{id: follower_id}, %User{id: followed_id}) do
__MODULE__
- |> where(follower_id: ^follower_id, following_id: ^followed_id, state: "accept")
+ |> where(follower_id: ^follower_id, following_id: ^followed_id, state: ^:follow_accept)
|> Repo.exists?()
end
@@ -97,7 +110,7 @@ def following(%User{} = user) do
__MODULE__
|> join(:inner, [r], u in User, on: r.following_id == u.id)
|> where([r], r.follower_id == ^user.id)
- |> where([r], r.state == "accept")
+ |> where([r], r.state == ^:follow_accept)
|> select([r, u], u.follower_address)
|> Repo.all()
@@ -157,4 +170,22 @@ def find(following_relationships, follower, following) do
fr -> fr.follower_id == follower.id and fr.following_id == following.id
end)
end
+
+ defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
+ changeset
+ |> validate_change(:following_id, fn _, following_id ->
+ if following_id == get_field(changeset, :follower_id) do
+ [target_id: "can't be equal to follower_id"]
+ else
+ []
+ end
+ end)
+ |> validate_change(:follower_id, fn _, follower_id ->
+ if follower_id == get_field(changeset, :following_id) do
+ [source_id: "can't be equal to following_id"]
+ else
+ []
+ end
+ end)
+ end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index d9aa54057..6ffb82045 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -697,7 +697,7 @@ def needs_update?(_), do: true
@spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
def maybe_direct_follow(%User{} = follower, %User{local: true, locked: true} = followed) do
- follow(follower, followed, "pending")
+ follow(follower, followed, :follow_pending)
end
def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) do
@@ -717,14 +717,14 @@ def maybe_direct_follow(%User{} = follower, %User{} = followed) do
def follow_all(follower, followeds) do
followeds
|> Enum.reject(fn followed -> blocks?(follower, followed) || blocks?(followed, follower) end)
- |> Enum.each(&follow(follower, &1, "accept"))
+ |> Enum.each(&follow(follower, &1, :follow_accept))
set_cache(follower)
end
defdelegate following(user), to: FollowingRelationship
- def follow(%User{} = follower, %User{} = followed, state \\ "accept") do
+ def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do
deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked])
cond do
@@ -751,7 +751,7 @@ def unfollow(%User{ap_id: ap_id}, %User{ap_id: ap_id}) do
def unfollow(%User{} = follower, %User{} = followed) do
case get_follow_state(follower, followed) do
- state when state in ["accept", "pending"] ->
+ state when state in [:follow_pending, :follow_accept] ->
FollowingRelationship.unfollow(follower, followed)
{:ok, followed} = update_follower_count(followed)
@@ -769,6 +769,7 @@ def unfollow(%User{} = follower, %User{} = followed) do
defdelegate following?(follower, followed), to: FollowingRelationship
+ @doc "Returns follow state as FollowingRelationshipStateEnum value"
def get_follow_state(%User{} = follower, %User{} = following) do
following_relationship = FollowingRelationship.get(follower, following)
get_follow_state(follower, following, following_relationship)
@@ -782,8 +783,11 @@ def get_follow_state(
case {following_relationship, following.local} do
{nil, false} ->
case Utils.fetch_latest_follow(follower, following) do
- %{data: %{"state" => state}} when state in ["pending", "accept"] -> state
- _ -> nil
+ %Activity{data: %{"state" => state}} when state in ["pending", "accept"] ->
+ FollowingRelationship.state_to_enum(state)
+
+ _ ->
+ nil
end
{%{state: state}, _} ->
@@ -1282,7 +1286,7 @@ def blocks?(nil, _), do: false
def blocks?(%User{} = user, %User{} = target) do
blocks_user?(user, target) ||
- (!User.following?(user, target) && blocks_domain?(user, target))
+ (blocks_domain?(user, target) and not User.following?(user, target))
end
def blocks_user?(%User{} = user, %User{} = target) do
diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex
index 884e33039..ec88088cf 100644
--- a/lib/pleroma/user/query.ex
+++ b/lib/pleroma/user/query.ex
@@ -148,7 +148,7 @@ defp compose_query({:followers, %User{id: id}}, query) do
as: :relationships,
on: r.following_id == ^id and r.follower_id == u.id
)
- |> where([relationships: r], r.state == "accept")
+ |> where([relationships: r], r.state == ^:follow_accept)
end
defp compose_query({:friends, %User{id: id}}, query) do
@@ -158,7 +158,7 @@ defp compose_query({:friends, %User{id: id}}, query) do
as: :relationships,
on: r.following_id == u.id and r.follower_id == ^id
)
- |> where([relationships: r], r.state == "accept")
+ |> where([relationships: r], r.state == ^:follow_accept)
end
defp compose_query({:recipients_from_activity, to}, query) do
@@ -173,7 +173,7 @@ defp compose_query({:recipients_from_activity, to}, query) do
)
|> where(
[u, following: f, relationships: r],
- u.ap_id in ^to or (f.follower_address in ^to and r.state == "accept")
+ u.ap_id in ^to or (f.follower_address in ^to and r.state == ^:follow_accept)
)
|> distinct(true)
end
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
index a0b3af432..f54647945 100644
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -33,7 +33,7 @@ def subdomains_regex(domains) when is_list(domains) do
@spec subdomain_match?([Regex.t()], String.t()) :: boolean()
def subdomain_match?(domains, host) do
- Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
+ !!Enum.find(domains, fn domain -> Regex.match?(domain, host) end)
end
@callback describe() :: {:ok | :error, Map.t()}
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index d6549a932..37e485741 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -490,7 +490,8 @@ def handle_incoming(
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
{_, {:ok, _}} <-
{:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")},
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+ {:ok, _relationship} <-
+ FollowingRelationship.update(follower, followed, :follow_accept) do
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
@@ -500,7 +501,7 @@ def handle_incoming(
else
{:user_blocked, true} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
ActivityPub.reject(%{
to: [follower.ap_id],
@@ -511,7 +512,7 @@ def handle_incoming(
{:follow, {:error, _}} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
ActivityPub.reject(%{
to: [follower.ap_id],
@@ -521,7 +522,7 @@ def handle_incoming(
})
{:user_locked, true} ->
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "pending")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_pending)
:noop
end
@@ -541,7 +542,7 @@ def handle_incoming(
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept) do
ActivityPub.accept(%{
to: follow_activity.data["to"],
type: "Accept",
@@ -564,7 +565,7 @@ def handle_incoming(
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
{:ok, activity} <-
ActivityPub.reject(%{
to: follow_activity.data["to"],
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 2646b9f7b..d530da42c 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -42,7 +42,7 @@ def accept_follow_request(follower, followed) do
with {:ok, follower} <- User.follow(follower, followed),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept),
{:ok, _activity} <-
ActivityPub.accept(%{
to: [follower.ap_id],
@@ -57,7 +57,7 @@ def accept_follow_request(follower, followed) do
def reject_follow_request(follower, followed) do
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
{:ok, _activity} <-
ActivityPub.reject(%{
to: [follower.ap_id],
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 0efcabc01..f2dc2a9bd 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -71,7 +71,7 @@ def render(
followed_by =
if following_relationships do
case FollowingRelationship.find(following_relationships, target, reading_user) do
- %{state: "accept"} -> true
+ %{state: :follow_accept} -> true
_ -> false
end
else
@@ -81,7 +81,7 @@ def render(
# NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
%{
id: to_string(target.id),
- following: follow_state == "accept",
+ following: follow_state == :follow_accept,
followed_by: followed_by,
blocking:
UserRelationship.exists?(
@@ -123,7 +123,7 @@ def render(
reading_user,
&User.subscribed_to?(&2, &1)
),
- requested: follow_state == "pending",
+ requested: follow_state == :follow_pending,
domain_blocking: User.blocks_domain?(reading_user, target),
showing_reblogs:
not UserRelationship.exists?(
diff --git a/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs b/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs
new file mode 100644
index 000000000..d5a431c00
--- /dev/null
+++ b/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs
@@ -0,0 +1,29 @@
+defmodule Pleroma.Repo.Migrations.ChangeFollowingRelationshipsStateToInteger do
+ use Ecto.Migration
+
+ @alter_apps_scopes "ALTER TABLE following_relationships ALTER COLUMN state"
+
+ def up do
+ execute("""
+ #{@alter_apps_scopes} TYPE integer USING
+ CASE
+ WHEN state = 'pending' THEN 1
+ WHEN state = 'accept' THEN 2
+ WHEN state = 'reject' THEN 3
+ ELSE 0
+ END;
+ """)
+ end
+
+ def down do
+ execute("""
+ #{@alter_apps_scopes} TYPE varchar(255) USING
+ CASE
+ WHEN state = 1 THEN 'pending'
+ WHEN state = 2 THEN 'accept'
+ WHEN state = 3 THEN 'reject'
+ ELSE ''
+ END;
+ """)
+ end
+end
diff --git a/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs b/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs
new file mode 100644
index 000000000..4c9faf48f
--- /dev/null
+++ b/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs
@@ -0,0 +1,11 @@
+defmodule Pleroma.Repo.Migrations.AddFollowingRelationshipsFollowingIdIndex do
+ use Ecto.Migration
+
+ # [:follower_index] index is useless because of [:follower_id, :following_id] index
+ # [:following_id] index makes sense because of user's followers-targeted queries
+ def change do
+ drop_if_exists(index(:following_relationships, [:follower_id]))
+
+ create_if_not_exists(drop_if_exists(index(:following_relationships, [:following_id])))
+ end
+end
diff --git a/test/following_relationship_test.exs b/test/following_relationship_test.exs
index 865bb3838..17a468abb 100644
--- a/test/following_relationship_test.exs
+++ b/test/following_relationship_test.exs
@@ -15,28 +15,28 @@ defmodule Pleroma.FollowingRelationshipTest do
test "returns following addresses without internal.fetch" do
user = insert(:user)
fetch_actor = InternalFetchActor.get_actor()
- FollowingRelationship.follow(fetch_actor, user, "accept")
+ FollowingRelationship.follow(fetch_actor, user, :follow_accept)
assert FollowingRelationship.following(fetch_actor) == [user.follower_address]
end
test "returns following addresses without relay" do
user = insert(:user)
relay_actor = Relay.get_actor()
- FollowingRelationship.follow(relay_actor, user, "accept")
+ FollowingRelationship.follow(relay_actor, user, :follow_accept)
assert FollowingRelationship.following(relay_actor) == [user.follower_address]
end
test "returns following addresses without remote user" do
user = insert(:user)
actor = insert(:user, local: false)
- FollowingRelationship.follow(actor, user, "accept")
+ FollowingRelationship.follow(actor, user, :follow_accept)
assert FollowingRelationship.following(actor) == [user.follower_address]
end
test "returns following addresses with local user" do
user = insert(:user)
actor = insert(:user, local: true)
- FollowingRelationship.follow(actor, user, "accept")
+ FollowingRelationship.follow(actor, user, :follow_accept)
assert FollowingRelationship.following(actor) == [
actor.follower_address,
diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs
index b45f37263..8df835b56 100644
--- a/test/tasks/user_test.exs
+++ b/test/tasks/user_test.exs
@@ -140,7 +140,7 @@ test "no user to toggle" do
test "user is unsubscribed" do
followed = insert(:user)
user = insert(:user)
- User.follow(user, followed, "accept")
+ User.follow(user, followed, :follow_accept)
Mix.Tasks.Pleroma.User.run(["unsubscribe", user.nickname])
diff --git a/test/user_test.exs b/test/user_test.exs
index 8055ebd08..e7dfc5980 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -194,7 +194,8 @@ test "doesn't return already accepted or duplicate follow requests" do
CommonAPI.follow(pending_follower, locked)
CommonAPI.follow(pending_follower, locked)
CommonAPI.follow(accepted_follower, locked)
- Pleroma.FollowingRelationship.update(accepted_follower, locked, "accept")
+
+ Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
assert [^pending_follower] = User.get_follow_requests(locked)
end
@@ -319,7 +320,7 @@ test "unfollow with syncronizes external user" do
following_address: "http://localhost:4001/users/fuser2/following"
})
- {:ok, user} = User.follow(user, followed, "accept")
+ {:ok, user} = User.follow(user, followed, :follow_accept)
{:ok, user, _activity} = User.unfollow(user, followed)
@@ -332,7 +333,7 @@ test "unfollow takes a user and another user" do
followed = insert(:user)
user = insert(:user)
- {:ok, user} = User.follow(user, followed, "accept")
+ {:ok, user} = User.follow(user, followed, :follow_accept)
assert User.following(user) == [user.follower_address, followed.follower_address]
@@ -353,7 +354,7 @@ test "unfollow doesn't unfollow yourself" do
test "test if a user is following another user" do
followed = insert(:user)
user = insert(:user)
- User.follow(user, followed, "accept")
+ User.follow(user, followed, :follow_accept)
assert User.following?(user, followed)
refute User.following?(followed, user)
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index b2cabbd30..b998f0d78 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -1622,7 +1622,7 @@ test "it upgrades a user to activitypub" do
})
user_two = insert(:user)
- Pleroma.FollowingRelationship.follow(user_two, user, "accept")
+ Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
{:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 0da0bd2e2..e53a7cedd 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -562,7 +562,7 @@ test "cancels a pending follow for a local user" do
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
CommonAPI.follow(follower, followed)
- assert User.get_follow_state(follower, followed) == "pending"
+ assert User.get_follow_state(follower, followed) == :follow_pending
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
assert User.get_follow_state(follower, followed) == nil
@@ -584,7 +584,7 @@ test "cancels a pending follow for a remote user" do
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
CommonAPI.follow(follower, followed)
- assert User.get_follow_state(follower, followed) == "pending"
+ assert User.get_follow_state(follower, followed) == :follow_pending
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
assert User.get_follow_state(follower, followed) == nil
diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/web/mastodon_api/controllers/follow_request_controller_test.exs
index dd848821a..d8dbe4800 100644
--- a/test/web/mastodon_api/controllers/follow_request_controller_test.exs
+++ b/test/web/mastodon_api/controllers/follow_request_controller_test.exs
@@ -21,7 +21,7 @@ test "/api/v1/follow_requests works", %{user: user, conn: conn} do
other_user = insert(:user)
{:ok, _activity} = ActivityPub.follow(other_user, user)
- {:ok, other_user} = User.follow(other_user, user, "pending")
+ {:ok, other_user} = User.follow(other_user, user, :follow_pending)
assert User.following?(other_user, user) == false
@@ -35,7 +35,7 @@ test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do
other_user = insert(:user)
{:ok, _activity} = ActivityPub.follow(other_user, user)
- {:ok, other_user} = User.follow(other_user, user, "pending")
+ {:ok, other_user} = User.follow(other_user, user, :follow_pending)
user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)
diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs
index a5d6e8ecf..ad8ce030b 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/web/streamer/streamer_test.exs
@@ -197,7 +197,7 @@ test "it doesn't send to user if recipients invalid and thread containment is en
Pleroma.Config.put([:instance, :skip_thread_containment], false)
author = insert(:user)
user = insert(:user)
- User.follow(user, author, "accept")
+ User.follow(user, author, :follow_accept)
activity =
insert(:note_activity,
@@ -220,7 +220,7 @@ test "it sends message if recipients invalid and thread containment is disabled"
Pleroma.Config.put([:instance, :skip_thread_containment], true)
author = insert(:user)
user = insert(:user)
- User.follow(user, author, "accept")
+ User.follow(user, author, :follow_accept)
activity =
insert(:note_activity,
@@ -243,7 +243,7 @@ test "it sends message if recipients invalid and thread containment is enabled b
Pleroma.Config.put([:instance, :skip_thread_containment], false)
author = insert(:user)
user = insert(:user, skip_thread_containment: true)
- User.follow(user, author, "accept")
+ User.follow(user, author, :follow_accept)
activity =
insert(:note_activity,
From 9c94b6a327118d8c7ea21355d6c378ef31c54321 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 30 Mar 2020 19:08:37 +0300
Subject: [PATCH 34/85] [#2332] Misc. fixes per code change requests.
---
lib/pleroma/web/activity_pub/mrf.ex | 2 +-
...328130139_add_following_relationships_following_id_index.exs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
index f54647945..a0b3af432 100644
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -33,7 +33,7 @@ def subdomains_regex(domains) when is_list(domains) do
@spec subdomain_match?([Regex.t()], String.t()) :: boolean()
def subdomain_match?(domains, host) do
- !!Enum.find(domains, fn domain -> Regex.match?(domain, host) end)
+ Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
end
@callback describe() :: {:ok | :error, Map.t()}
diff --git a/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs b/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs
index 4c9faf48f..884832f84 100644
--- a/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs
+++ b/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs
@@ -6,6 +6,6 @@ defmodule Pleroma.Repo.Migrations.AddFollowingRelationshipsFollowingIdIndex do
def change do
drop_if_exists(index(:following_relationships, [:follower_id]))
- create_if_not_exists(drop_if_exists(index(:following_relationships, [:following_id])))
+ create_if_not_exists(index(:following_relationships, [:following_id]))
end
end
From ea9c57b26ed463622e4489736fcddb8fca1b3341 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Tue, 31 Mar 2020 09:21:42 +0300
Subject: [PATCH 35/85] [#2332] Misc. improvements per code change requests.
---
lib/pleroma/ecto_enums.ex | 4 +-
lib/pleroma/following_relationship.ex | 42 +++++++++++--------
lib/pleroma/user.ex | 2 +-
lib/pleroma/user_relationship.ex | 33 +++++++++------
...llowing_relationships_state_to_integer.exs | 6 +--
5 files changed, 52 insertions(+), 35 deletions(-)
diff --git a/lib/pleroma/ecto_enums.ex b/lib/pleroma/ecto_enums.ex
index b98ac4ba1..6fc47620c 100644
--- a/lib/pleroma/ecto_enums.ex
+++ b/lib/pleroma/ecto_enums.ex
@@ -4,7 +4,7 @@
import EctoEnum
-defenum(UserRelationshipTypeEnum,
+defenum(Pleroma.UserRelationship.Type,
block: 1,
mute: 2,
reblog_mute: 3,
@@ -12,7 +12,7 @@
inverse_subscription: 5
)
-defenum(FollowingRelationshipStateEnum,
+defenum(Pleroma.FollowingRelationship.State,
follow_pending: 1,
follow_accept: 2,
follow_reject: 3
diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex
index a28da8bec..9ccf40495 100644
--- a/lib/pleroma/following_relationship.ex
+++ b/lib/pleroma/following_relationship.ex
@@ -8,12 +8,13 @@ defmodule Pleroma.FollowingRelationship do
import Ecto.Changeset
import Ecto.Query
+ alias Ecto.Changeset
alias FlakeId.Ecto.CompatType
alias Pleroma.Repo
alias Pleroma.User
schema "following_relationships" do
- field(:state, FollowingRelationshipStateEnum, default: :follow_pending)
+ field(:state, Pleroma.FollowingRelationship.State, default: :follow_pending)
belongs_to(:follower, User, type: CompatType)
belongs_to(:following, User, type: CompatType)
@@ -33,13 +34,12 @@ def changeset(%__MODULE__{} = following_relationship, attrs) do
|> validate_not_self_relationship()
end
- def state_to_enum(state) when is_binary(state) do
- case state do
- "pending" -> :follow_pending
- "accept" -> :follow_accept
- "reject" -> :follow_reject
- _ -> raise "State is not convertible to FollowingRelationshipStateEnum: #{state}"
- end
+ def state_to_enum(state) when state in ["pending", "accept", "reject"] do
+ String.to_existing_atom("follow_#{state}")
+ end
+
+ def state_to_enum(state) do
+ raise "State is not convertible to Pleroma.FollowingRelationship.State: #{state}"
end
def get(%User{} = follower, %User{} = following) do
@@ -171,16 +171,14 @@ def find(following_relationships, follower, following) do
end)
end
- defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
+ defp validate_not_self_relationship(%Changeset{} = changeset) do
changeset
- |> validate_change(:following_id, fn _, following_id ->
- if following_id == get_field(changeset, :follower_id) do
- [target_id: "can't be equal to follower_id"]
- else
- []
- end
- end)
- |> validate_change(:follower_id, fn _, follower_id ->
+ |> validate_follower_id_following_id_inequality()
+ |> validate_following_id_follower_id_inequality()
+ end
+
+ defp validate_follower_id_following_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :follower_id, fn _, follower_id ->
if follower_id == get_field(changeset, :following_id) do
[source_id: "can't be equal to following_id"]
else
@@ -188,4 +186,14 @@ defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
end
end)
end
+
+ defp validate_following_id_follower_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :following_id, fn _, following_id ->
+ if following_id == get_field(changeset, :follower_id) do
+ [target_id: "can't be equal to follower_id"]
+ else
+ []
+ end
+ end)
+ end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 6ffb82045..4f3abd7d5 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -769,7 +769,7 @@ def unfollow(%User{} = follower, %User{} = followed) do
defdelegate following?(follower, followed), to: FollowingRelationship
- @doc "Returns follow state as FollowingRelationshipStateEnum value"
+ @doc "Returns follow state as Pleroma.FollowingRelationship.State value"
def get_follow_state(%User{} = follower, %User{} = following) do
following_relationship = FollowingRelationship.get(follower, following)
get_follow_state(follower, following, following_relationship)
diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex
index 18a5eec72..ad0d303b1 100644
--- a/lib/pleroma/user_relationship.ex
+++ b/lib/pleroma/user_relationship.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.UserRelationship do
import Ecto.Changeset
import Ecto.Query
+ alias Ecto.Changeset
alias Pleroma.FollowingRelationship
alias Pleroma.Repo
alias Pleroma.User
@@ -16,12 +17,12 @@ defmodule Pleroma.UserRelationship do
schema "user_relationships" do
belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
belongs_to(:target, User, type: FlakeId.Ecto.CompatType)
- field(:relationship_type, UserRelationshipTypeEnum)
+ field(:relationship_type, Pleroma.UserRelationship.Type)
timestamps(updated_at: false)
end
- for relationship_type <- Keyword.keys(UserRelationshipTypeEnum.__enum_map__()) do
+ for relationship_type <- Keyword.keys(Pleroma.UserRelationship.Type.__enum_map__()) do
# `def create_block/2`, `def create_mute/2`, `def create_reblog_mute/2`,
# `def create_notification_mute/2`, `def create_inverse_subscription/2`
def unquote(:"create_#{relationship_type}")(source, target),
@@ -40,7 +41,7 @@ def unquote(:"#{relationship_type}_exists?")(source, target),
def user_relationship_types, do: Keyword.keys(user_relationship_mappings())
- def user_relationship_mappings, do: UserRelationshipTypeEnum.__enum_map__()
+ def user_relationship_mappings, do: Pleroma.UserRelationship.Type.__enum_map__()
def changeset(%UserRelationship{} = user_relationship, params \\ %{}) do
user_relationship
@@ -147,16 +148,14 @@ def view_relationships_option(%User{} = reading_user, actors) do
%{user_relationships: user_relationships, following_relationships: following_relationships}
end
- defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
+ defp validate_not_self_relationship(%Changeset{} = changeset) do
changeset
- |> validate_change(:target_id, fn _, target_id ->
- if target_id == get_field(changeset, :source_id) do
- [target_id: "can't be equal to source_id"]
- else
- []
- end
- end)
- |> validate_change(:source_id, fn _, source_id ->
+ |> validate_source_id_target_id_inequality()
+ |> validate_target_id_source_id_inequality()
+ end
+
+ defp validate_source_id_target_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :source_id, fn _, source_id ->
if source_id == get_field(changeset, :target_id) do
[source_id: "can't be equal to target_id"]
else
@@ -164,4 +163,14 @@ defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
end
end)
end
+
+ defp validate_target_id_source_id_inequality(%Changeset{} = changeset) do
+ validate_change(changeset, :target_id, fn _, target_id ->
+ if target_id == get_field(changeset, :source_id) do
+ [target_id: "can't be equal to source_id"]
+ else
+ []
+ end
+ end)
+ end
end
diff --git a/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs b/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs
index d5a431c00..2b0820f3f 100644
--- a/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs
+++ b/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs
@@ -1,11 +1,11 @@
defmodule Pleroma.Repo.Migrations.ChangeFollowingRelationshipsStateToInteger do
use Ecto.Migration
- @alter_apps_scopes "ALTER TABLE following_relationships ALTER COLUMN state"
+ @alter_following_relationship_state "ALTER TABLE following_relationships ALTER COLUMN state"
def up do
execute("""
- #{@alter_apps_scopes} TYPE integer USING
+ #{@alter_following_relationship_state} TYPE integer USING
CASE
WHEN state = 'pending' THEN 1
WHEN state = 'accept' THEN 2
@@ -17,7 +17,7 @@ def up do
def down do
execute("""
- #{@alter_apps_scopes} TYPE varchar(255) USING
+ #{@alter_following_relationship_state} TYPE varchar(255) USING
CASE
WHEN state = 1 THEN 'pending'
WHEN state = 2 THEN 'accept'
From f6835333be745cd411b5d2571c304fc7a16d645e Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 12:55:25 +0000
Subject: [PATCH 36/85] Apply suggestion to
lib/pleroma/web/activity_pub/transmogrifier.ex
---
lib/pleroma/web/activity_pub/transmogrifier.ex | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index dbb14e9aa..23148b2a0 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -615,8 +615,7 @@ def handle_incoming(%{"type" => "Like"} = data, _options) do
with {_, {:ok, cast_data_sym}} <-
{:casting_data,
data |> LikeValidator.cast_data() |> Ecto.Changeset.apply_action(:insert)},
- {_, cast_data} <-
- {:stringify_keys, ObjectValidator.stringify_keys(cast_data_sym |> Map.from_struct())},
+ cast_data = ObjectValidator.stringify_keys(Map.from_struct(cast_data_sym)),
:ok <- ObjectValidator.fetch_actor_and_object(cast_data),
{_, {:ok, cast_data}} <- {:maybe_add_context, maybe_add_context_from_object(cast_data)},
{_, {:ok, cast_data}} <-
From d191b0942f64a32a2bf450318fac85981aa17c83 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Tue, 31 Mar 2020 22:48:42 +0900
Subject: [PATCH 37/85] Remove no longer used function
---
lib/pleroma/user.ex | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index d9aa54057..6644d6b66 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1983,17 +1983,6 @@ def fields(%{fields: nil}), do: []
def fields(%{fields: fields}), do: fields
- def sanitized_fields(%User{} = user) do
- user
- |> User.fields()
- |> Enum.map(fn %{"name" => name, "value" => value} ->
- %{
- "name" => name,
- "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
- }
- end)
- end
-
def validate_fields(changeset, remote? \\ false) do
limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields
limit = Pleroma.Config.get([:instance, limit_name], 0)
From 643f15e77b7cdaaf2c22a876c98e5680edc32dc3 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 16:11:38 +0200
Subject: [PATCH 38/85] Validators: ObjectID is an http uri.
---
.../object_validators/types/object.ex | 16 ++++++--
.../types/object_id_test.exs | 38 +++++++++++++++++++
2 files changed, 50 insertions(+), 4 deletions(-)
create mode 100644 test/web/activity_pub/object_validators/types/object_id_test.exs
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/object.ex b/lib/pleroma/web/activity_pub/object_validators/types/object.ex
index 92fc13ba8..8e70effe4 100644
--- a/lib/pleroma/web/activity_pub/object_validators/types/object.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/types/object.ex
@@ -4,12 +4,20 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID do
def type, do: :string
def cast(object) when is_binary(object) do
- {:ok, object}
+ with %URI{
+ scheme: scheme,
+ host: host
+ }
+ when scheme in ["https", "http"] and not is_nil(host) <-
+ URI.parse(object) do
+ {:ok, object}
+ else
+ _ ->
+ :error
+ end
end
- def cast(%{"id" => object}) when is_binary(object) do
- {:ok, object}
- end
+ def cast(%{"id" => object}), do: cast(object)
def cast(_) do
:error
diff --git a/test/web/activity_pub/object_validators/types/object_id_test.exs b/test/web/activity_pub/object_validators/types/object_id_test.exs
new file mode 100644
index 000000000..f4c5ed1dc
--- /dev/null
+++ b/test/web/activity_pub/object_validators/types/object_id_test.exs
@@ -0,0 +1,38 @@
+defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID
+ use Pleroma.DataCase
+
+ @uris [
+ "http://lain.com/users/lain",
+ "http://lain.com",
+ "https://lain.com/object/1"
+ ]
+
+ @non_uris [
+ "https://",
+ "rin"
+ ]
+
+ test "it rejects integers" do
+ assert :error == ObjectID.cast(1)
+ end
+
+ test "it accepts http uris" do
+ Enum.each(@uris, fn uri ->
+ assert {:ok, uri} == ObjectID.cast(uri)
+ end)
+ end
+
+ test "it accepts an object with a nested uri id" do
+ Enum.each(@uris, fn uri ->
+ assert {:ok, uri} == ObjectID.cast(%{"id" => uri})
+ end)
+ end
+
+ test "it rejects non-uri strings" do
+ Enum.each(@non_uris, fn non_uri ->
+ assert :error == ObjectID.cast(non_uri)
+ assert :error == ObjectID.cast(%{"id" => non_uri})
+ end)
+ end
+end
From df5f89c0d6d8d385434d5d8a51719fa41631d7b2 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Tue, 31 Mar 2020 18:22:25 +0300
Subject: [PATCH 39/85] test for default features and changelog entry
---
CHANGELOG.md | 1 +
test/web/node_info_test.exs | 92 +++++++++++++++++++------------------
2 files changed, 49 insertions(+), 44 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 350e03894..747d84d48 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/).
### Added
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
+- NodeInfo: `pleroma_emoji_reactions` to the `features` list.
- Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
API Changes
diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs
index e5eebced1..9bcc07b37 100644
--- a/test/web/node_info_test.exs
+++ b/test/web/node_info_test.exs
@@ -7,6 +7,8 @@ defmodule Pleroma.Web.NodeInfoTest do
import Pleroma.Factory
+ alias Pleroma.Config
+
setup do: clear_config([:mrf_simple])
setup do: clear_config(:instance)
@@ -47,7 +49,7 @@ test "nodeinfo shows restricted nicknames", %{conn: conn} do
assert result = json_response(conn, 200)
- assert Pleroma.Config.get([Pleroma.User, :restricted_nicknames]) ==
+ assert Config.get([Pleroma.User, :restricted_nicknames]) ==
result["metadata"]["restrictedNicknames"]
end
@@ -65,10 +67,10 @@ test "returns software.repository field in nodeinfo 2.1", %{conn: conn} do
end
test "returns fieldsLimits field", %{conn: conn} do
- Pleroma.Config.put([:instance, :max_account_fields], 10)
- Pleroma.Config.put([:instance, :max_remote_account_fields], 15)
- Pleroma.Config.put([:instance, :account_field_name_length], 255)
- Pleroma.Config.put([:instance, :account_field_value_length], 2048)
+ Config.put([:instance, :max_account_fields], 10)
+ Config.put([:instance, :max_remote_account_fields], 15)
+ Config.put([:instance, :account_field_name_length], 255)
+ Config.put([:instance, :account_field_value_length], 2048)
response =
conn
@@ -82,8 +84,8 @@ test "returns fieldsLimits field", %{conn: conn} do
end
test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
- option = Pleroma.Config.get([:instance, :safe_dm_mentions])
- Pleroma.Config.put([:instance, :safe_dm_mentions], true)
+ option = Config.get([:instance, :safe_dm_mentions])
+ Config.put([:instance, :safe_dm_mentions], true)
response =
conn
@@ -92,7 +94,7 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
assert "safe_dm_mentions" in response["metadata"]["features"]
- Pleroma.Config.put([:instance, :safe_dm_mentions], false)
+ Config.put([:instance, :safe_dm_mentions], false)
response =
conn
@@ -101,14 +103,14 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
refute "safe_dm_mentions" in response["metadata"]["features"]
- Pleroma.Config.put([:instance, :safe_dm_mentions], option)
+ Config.put([:instance, :safe_dm_mentions], option)
end
describe "`metadata/federation/enabled`" do
setup do: clear_config([:instance, :federating])
test "it shows if federation is enabled/disabled", %{conn: conn} do
- Pleroma.Config.put([:instance, :federating], true)
+ Config.put([:instance, :federating], true)
response =
conn
@@ -117,7 +119,7 @@ test "it shows if federation is enabled/disabled", %{conn: conn} do
assert response["metadata"]["federation"]["enabled"] == true
- Pleroma.Config.put([:instance, :federating], false)
+ Config.put([:instance, :federating], false)
response =
conn
@@ -134,31 +136,33 @@ test "it shows default features flags", %{conn: conn} do
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
- assert response["metadata"]["features"] --
- [
- "pleroma_api",
- "mastodon_api",
- "mastodon_api_streaming",
- "polls",
- "pleroma_explicit_addressing",
- "shareable_emoji_packs",
- "multifetch",
- "chat",
- "relay",
- "pleroma_emoji_reactions",
- "pleroma:api/v1/notifications:include_types_filter"
- ] == []
+ default_features = [
+ "pleroma_api",
+ "mastodon_api",
+ "mastodon_api_streaming",
+ "polls",
+ "pleroma_explicit_addressing",
+ "shareable_emoji_packs",
+ "multifetch",
+ "pleroma_emoji_reactions",
+ "pleroma:api/v1/notifications:include_types_filter"
+ ]
+
+ assert MapSet.subset?(
+ MapSet.new(default_features),
+ MapSet.new(response["metadata"]["features"])
+ )
end
test "it shows MRF transparency data if enabled", %{conn: conn} do
- config = Pleroma.Config.get([:instance, :rewrite_policy])
- Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
+ config = Config.get([:instance, :rewrite_policy])
+ Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
- option = Pleroma.Config.get([:instance, :mrf_transparency])
- Pleroma.Config.put([:instance, :mrf_transparency], true)
+ option = Config.get([:instance, :mrf_transparency])
+ Config.put([:instance, :mrf_transparency], true)
simple_config = %{"reject" => ["example.com"]}
- Pleroma.Config.put(:mrf_simple, simple_config)
+ Config.put(:mrf_simple, simple_config)
response =
conn
@@ -167,25 +171,25 @@ test "it shows MRF transparency data if enabled", %{conn: conn} do
assert response["metadata"]["federation"]["mrf_simple"] == simple_config
- Pleroma.Config.put([:instance, :rewrite_policy], config)
- Pleroma.Config.put([:instance, :mrf_transparency], option)
- Pleroma.Config.put(:mrf_simple, %{})
+ Config.put([:instance, :rewrite_policy], config)
+ Config.put([:instance, :mrf_transparency], option)
+ Config.put(:mrf_simple, %{})
end
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
- config = Pleroma.Config.get([:instance, :rewrite_policy])
- Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
+ config = Config.get([:instance, :rewrite_policy])
+ Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
- option = Pleroma.Config.get([:instance, :mrf_transparency])
- Pleroma.Config.put([:instance, :mrf_transparency], true)
+ option = Config.get([:instance, :mrf_transparency])
+ Config.put([:instance, :mrf_transparency], true)
- exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions])
- Pleroma.Config.put([:instance, :mrf_transparency_exclusions], ["other.site"])
+ exclusions = Config.get([:instance, :mrf_transparency_exclusions])
+ Config.put([:instance, :mrf_transparency_exclusions], ["other.site"])
simple_config = %{"reject" => ["example.com", "other.site"]}
expected_config = %{"reject" => ["example.com"]}
- Pleroma.Config.put(:mrf_simple, simple_config)
+ Config.put(:mrf_simple, simple_config)
response =
conn
@@ -195,9 +199,9 @@ test "it performs exclusions from MRF transparency data if configured", %{conn:
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
assert response["metadata"]["federation"]["exclusions"] == true
- Pleroma.Config.put([:instance, :rewrite_policy], config)
- Pleroma.Config.put([:instance, :mrf_transparency], option)
- Pleroma.Config.put([:instance, :mrf_transparency_exclusions], exclusions)
- Pleroma.Config.put(:mrf_simple, %{})
+ Config.put([:instance, :rewrite_policy], config)
+ Config.put([:instance, :mrf_transparency], option)
+ Config.put([:instance, :mrf_transparency_exclusions], exclusions)
+ Config.put(:mrf_simple, %{})
end
end
From 7af0959a07ebd5f8242704658ccb770d86fdb4c6 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Tue, 31 Mar 2020 18:30:19 +0300
Subject: [PATCH 40/85] updating docs
---
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 12e63ef9f..90c43c356 100644
--- a/docs/API/pleroma_api.md
+++ b/docs/API/pleroma_api.md
@@ -431,7 +431,7 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa
# Emoji Reactions
-Emoji reactions work a lot like favourites do. They make it possible to react to a post with a single emoji character.
+Emoji reactions work a lot like favourites do. They make it possible to react to a post with a single emoji character. To detect the presence of this feature, you can check `pleroma_emoji_reactions` entry in the features list of nodeinfo.
## `PUT /api/v1/pleroma/statuses/:id/reactions/:emoji`
### React to a post with a unicode emoji
From aebec1bac9831da2bed5ee571225d92dc99a5d59 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 17:47:34 +0200
Subject: [PATCH 41/85] Validator Test: Small refactor.
---
.../object_validators/types/object_id_test.exs | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/test/web/activity_pub/object_validators/types/object_id_test.exs b/test/web/activity_pub/object_validators/types/object_id_test.exs
index f4c5ed1dc..834213182 100644
--- a/test/web/activity_pub/object_validators/types/object_id_test.exs
+++ b/test/web/activity_pub/object_validators/types/object_id_test.exs
@@ -10,13 +10,12 @@ defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do
@non_uris [
"https://",
- "rin"
+ "rin",
+ 1,
+ :x,
+ %{"1" => 2}
]
- test "it rejects integers" do
- assert :error == ObjectID.cast(1)
- end
-
test "it accepts http uris" do
Enum.each(@uris, fn uri ->
assert {:ok, uri} == ObjectID.cast(uri)
From 057438a657eaadb963e006b84b890ae4f8441808 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 17:56:05 +0200
Subject: [PATCH 42/85] CommonAPI: DRY up a bit.
---
lib/pleroma/web/common_api/common_api.ex | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index f882f9fcb..74adcca55 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -112,8 +112,22 @@ def unrepeat(id_or_ap_id, user) do
end
end
- @spec favorite(User.t(), binary()) :: {:ok, Activity.t()} | {:error, any()}
+ @spec favorite(User.t(), binary()) :: {:ok, Activity.t() | :already_liked} | {:error, any()}
def favorite(%User{} = user, id) do
+ case favorite_helper(user, id) do
+ {:ok, _} = res ->
+ res
+
+ {:error, :not_found} = res ->
+ res
+
+ {:error, e} ->
+ Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
+ {:error, dgettext("errors", "Could not favorite")}
+ end
+ end
+
+ def favorite_helper(user, id) do
with {_, %Activity{object: object}} <- {:find_object, Activity.get_by_id_with_object(id)},
{_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
{_, {:ok, %Activity{} = activity, _meta}} <-
@@ -138,13 +152,11 @@ def favorite(%User{} = user, id) do
if {:object, {"already liked by this actor", []}} in changeset.errors do
{:ok, :already_liked}
else
- Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
- {:error, dgettext("errors", "Could not favorite"), e}
+ {:error, e}
end
e ->
- Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
- {:error, dgettext("errors", "Could not favorite"), e}
+ {:error, e}
end
end
From 0be1fa0a8695df87a8b22279b885956943e33796 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 17:00:48 +0000
Subject: [PATCH 43/85] Apply suggestion to
lib/pleroma/web/activity_pub/transmogrifier.ex
---
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 23148b2a0..fb41ec8e9 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -1291,6 +1291,6 @@ defp maybe_add_recipients_from_object(%{"object" => object} = data) do
end
defp maybe_add_recipients_from_object(_) do
- {:error, "No referenced object"}
+ {:error, :no_object}
end
end
From 288f2b5a7c728959d43205a97d5225b34b5b8161 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 17:00:55 +0000
Subject: [PATCH 44/85] Apply suggestion to
lib/pleroma/web/activity_pub/transmogrifier.ex
---
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 fb41ec8e9..a3529f09b 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -1267,7 +1267,7 @@ defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(
end
defp maybe_add_context_from_object(_) do
- {:error, "No referenced object"}
+ {:error, :no_context}
end
defp maybe_add_recipients_from_object(%{"object" => object} = data) do
From ecac57732a063c1ad01aeb5aa4eb9853b6f904e9 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 19:16:45 +0200
Subject: [PATCH 45/85] Transmogrifier: Only add context if it really is onne.
---
lib/pleroma/web/activity_pub/transmogrifier.ex | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index a3529f09b..f82142979 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -1255,14 +1255,11 @@ defp maybe_add_context_from_object(%{"context" => context} = data) when is_binar
do: {:ok, data}
defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(object) do
- if object = Object.normalize(object) do
- data =
- data
- |> Map.put("context", object.data["context"])
-
- {:ok, data}
+ with %{data: %{"context" => context}} when is_binary(context) <- Object.normalize(object) do
+ {:ok, Map.put(data, "context", context)}
else
- {:error, "No context on referenced object"}
+ _ ->
+ {:error, :no_context}
end
end
From 1b323ce1c668c6a26617a05dcc12ee255c764e88 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 17:28:18 +0000
Subject: [PATCH 46/85] Apply suggestion to
lib/pleroma/web/activity_pub/transmogrifier.ex
---
.../web/activity_pub/transmogrifier.ex | 21 +++++++------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index f82142979..a18ece6e7 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -1267,24 +1267,19 @@ defp maybe_add_context_from_object(_) do
{:error, :no_context}
end
- defp maybe_add_recipients_from_object(%{"object" => object} = data) do
- to = data["to"] || []
- cc = data["cc"] || []
+ defp maybe_add_recipients_from_object(%{"to" => [_ | _], "cc" => [_ | _]} = data), do: {:ok, data}
- if to == [] && cc == [] do
- if object = Object.normalize(object) do
+ defp maybe_add_recipients_from_object(%{"object" => object} = data) do
+ case Object.normalize(object) do
+ %{data: {"actor" => actor}} ->
data =
data
- |> Map.put("to", [object.data["actor"]])
- |> Map.put("cc", cc)
+ |> Map.put("to", [actor])
+ |> Map.put("cc", data["cc"] || [])
{:ok, data}
- else
- {:error, "No actor on referenced object"}
- end
- else
- {:ok, data}
- end
+ nil -> {:error, :no_object}
+ _ -> {:error, :no_actor}
end
defp maybe_add_recipients_from_object(_) do
From c982093cc2f538e8ef9dde365e163a944c6cb6d0 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 31 Mar 2020 19:33:41 +0200
Subject: [PATCH 47/85] Transmogrifier: Fix BAD code by RINPATCH
---
lib/pleroma/web/activity_pub/transmogrifier.ex | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index a18ece6e7..a4b385cd5 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -1267,19 +1267,25 @@ defp maybe_add_context_from_object(_) do
{:error, :no_context}
end
- defp maybe_add_recipients_from_object(%{"to" => [_ | _], "cc" => [_ | _]} = data), do: {:ok, data}
+ defp maybe_add_recipients_from_object(%{"to" => [_ | _], "cc" => [_ | _]} = data),
+ do: {:ok, data}
defp maybe_add_recipients_from_object(%{"object" => object} = data) do
case Object.normalize(object) do
- %{data: {"actor" => actor}} ->
+ %{data: %{"actor" => actor}} ->
data =
data
|> Map.put("to", [actor])
|> Map.put("cc", data["cc"] || [])
{:ok, data}
- nil -> {:error, :no_object}
- _ -> {:error, :no_actor}
+
+ nil ->
+ {:error, :no_object}
+
+ _ ->
+ {:error, :no_actor}
+ end
end
defp maybe_add_recipients_from_object(_) do
From dbf9d719f98770056ac906b3087e7ed501cd64e6 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Wed, 1 Apr 2020 00:05:13 +0900
Subject: [PATCH 48/85] split test for update profile fields
---
.../update_credentials_test.exs | 98 ++++++++++---------
1 file changed, 53 insertions(+), 45 deletions(-)
diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
index b693c1a47..8687d7995 100644
--- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
+++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
@@ -273,7 +273,7 @@ test "updates profile emojos", %{user: user, conn: conn} do
test "update fields", %{conn: conn} do
fields = [
%{"name" => "foo", "value" => ""},
- %{"name" => "link", "value" => "cofe.io"}
+ %{"name" => "link.io", "value" => "cofe.io"}
]
account_data =
@@ -283,7 +283,10 @@ test "update fields", %{conn: conn} do
assert account_data["fields"] == [
%{"name" => "foo", "value" => "bar"},
- %{"name" => "link", "value" => ~S(cofe.io)}
+ %{
+ "name" => "link.io",
+ "value" => ~S(cofe.io)
+ }
]
assert account_data["source"]["fields"] == [
@@ -291,14 +294,16 @@ test "update fields", %{conn: conn} do
"name" => "foo",
"value" => ""
},
- %{"name" => "link", "value" => "cofe.io"}
+ %{"name" => "link.io", "value" => "cofe.io"}
]
+ end
+ test "update fields by urlencoded", %{conn: conn} do
fields =
[
"fields_attributes[1][name]=link",
- "fields_attributes[1][value]=cofe.io",
- "fields_attributes[0][name]=foo",
+ "fields_attributes[1][value]=http://cofe.io",
+ "fields_attributes[0][name]=foo",
"fields_attributes[0][value]=bar"
]
|> Enum.join("&")
@@ -310,51 +315,20 @@ test "update fields", %{conn: conn} do
|> json_response(200)
assert account["fields"] == [
- %{"name" => "foo", "value" => "bar"},
- %{"name" => "link", "value" => ~S(cofe.io)}
+ %{"name" => "foo", "value" => "bar"},
+ %{
+ "name" => "link",
+ "value" => ~S(http://cofe.io)
+ }
]
assert account["source"]["fields"] == [
- %{
- "name" => "foo",
- "value" => "bar"
- },
- %{"name" => "link", "value" => "cofe.io"}
+ %{"name" => "foo", "value" => "bar"},
+ %{"name" => "link", "value" => "http://cofe.io"}
]
+ end
- name_limit = Pleroma.Config.get([:instance, :account_field_name_length])
- value_limit = Pleroma.Config.get([:instance, :account_field_value_length])
-
- long_value = Enum.map(0..value_limit, fn _ -> "x" end) |> Enum.join()
-
- fields = [%{"name" => "foo", "value" => long_value}]
-
- assert %{"error" => "Invalid request"} ==
- conn
- |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})
- |> json_response(403)
-
- long_name = Enum.map(0..name_limit, fn _ -> "x" end) |> Enum.join()
-
- fields = [%{"name" => long_name, "value" => "bar"}]
-
- assert %{"error" => "Invalid request"} ==
- conn
- |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})
- |> json_response(403)
-
- Pleroma.Config.put([:instance, :max_account_fields], 1)
-
- fields = [
- %{"name" => "foo", "value" => "bar"},
- %{"name" => "link", "value" => "cofe.io"}
- ]
-
- assert %{"error" => "Invalid request"} ==
- conn
- |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})
- |> json_response(403)
-
+ test "update fields with empty name", %{conn: conn} do
fields = [
%{"name" => "foo", "value" => ""},
%{"name" => "", "value" => "bar"}
@@ -369,5 +343,39 @@ test "update fields", %{conn: conn} do
%{"name" => "foo", "value" => ""}
]
end
+
+ test "update fields when invalid request", %{conn: conn} do
+ name_limit = Pleroma.Config.get([:instance, :account_field_name_length])
+ value_limit = Pleroma.Config.get([:instance, :account_field_value_length])
+
+ long_name = Enum.map(0..name_limit, fn _ -> "x" end) |> Enum.join()
+ long_value = Enum.map(0..value_limit, fn _ -> "x" end) |> Enum.join()
+
+ fields = [%{"name" => "foo", "value" => long_value}]
+
+ assert %{"error" => "Invalid request"} ==
+ conn
+ |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})
+ |> json_response(403)
+
+ fields = [%{"name" => long_name, "value" => "bar"}]
+
+ assert %{"error" => "Invalid request"} ==
+ conn
+ |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})
+ |> json_response(403)
+
+ Pleroma.Config.put([:instance, :max_account_fields], 1)
+
+ fields = [
+ %{"name" => "foo", "value" => "bar"},
+ %{"name" => "link", "value" => "cofe.io"}
+ ]
+
+ assert %{"error" => "Invalid request"} ==
+ conn
+ |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})
+ |> json_response(403)
+ end
end
end
From 7408f003a663c5f634cabad963c0446ba54810bf Mon Sep 17 00:00:00 2001
From: kPherox
Date: Tue, 31 Mar 2020 11:13:53 +0000
Subject: [PATCH 49/85] Use `Pleroma.Formatter.linkify` instead of
`AutoLinker.link`
---
lib/pleroma/user.ex | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 6644d6b66..c29935871 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -16,6 +16,7 @@ defmodule Pleroma.User do
alias Pleroma.Conversation.Participation
alias Pleroma.Delivery
alias Pleroma.FollowingRelationship
+ alias Pleroma.Formatter
alias Pleroma.HTML
alias Pleroma.Keys
alias Pleroma.Notification
@@ -456,7 +457,7 @@ defp put_fields(changeset) do
fields =
raw_fields
- |> Enum.map(fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end)
+ |> Enum.map(fn f -> Map.update!(f, "value", &parse_fields(&1)) end)
changeset
|> put_change(:raw_fields, raw_fields)
@@ -466,6 +467,12 @@ defp put_fields(changeset) do
end
end
+ defp parse_fields(value) do
+ value
+ |> Formatter.linkify(mentions_format: :full)
+ |> elem(0)
+ end
+
defp put_change_if_present(changeset, map_field, value_function) do
if value = get_change(changeset, map_field) do
with {:ok, new_value} <- value_function.(value) do
From 037b49c415060b4c7ad5a570da80857b4d2c43f1 Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 1 Apr 2020 16:10:17 +0200
Subject: [PATCH 50/85] Validators: Correct ObjectID filename
---
.../object_validators/types/{object.ex => object_id.ex} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename lib/pleroma/web/activity_pub/object_validators/types/{object.ex => object_id.ex} (100%)
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/object.ex b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
similarity index 100%
rename from lib/pleroma/web/activity_pub/object_validators/types/object.ex
rename to lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
From 2d64500a9dee8bc53c988719bde1c1f4f41575b7 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Wed, 1 Apr 2020 20:26:33 +0300
Subject: [PATCH 51/85] error improvement for email_invite endpoint
---
docs/API/admin_api.md | 13 +++++++
.../web/admin_api/admin_api_controller.ex | 17 ++++++--
.../admin_api/admin_api_controller_test.exs | 39 ++++++++++++++++++-
3 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md
index edcf73e14..179d8c451 100644
--- a/docs/API/admin_api.md
+++ b/docs/API/admin_api.md
@@ -392,6 +392,19 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
- `email`
- `name`, optional
+- Response:
+ - On success: `204`, empty response
+ - On failure:
+ - 400 Bad Request, JSON:
+
+ ```json
+ [
+ {
+ `error` // error message
+ }
+ ]
+ ```
+
## `GET /api/pleroma/admin/users/:nickname/password_reset`
### Get a password reset token for a given nickname
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index ca5439920..7b442f6e1 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -576,9 +576,8 @@ def relay_unfollow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target})
@doc "Sends registration invite via email"
def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
- with true <-
- Config.get([:instance, :invites_enabled]) &&
- !Config.get([:instance, :registrations_open]),
+ with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
+ {_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
{:ok, invite_token} <- UserInviteToken.create_invite(),
email <-
Pleroma.Emails.UserEmail.user_invitation_email(
@@ -589,6 +588,18 @@ def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params)
),
{:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
json_response(conn, :no_content, "")
+ else
+ {:registrations_open, _} ->
+ errors(
+ conn,
+ {:error, "To send invites you need set `registrations_open` option to false."}
+ )
+
+ {:invites_enabled, _} ->
+ errors(
+ conn,
+ {:error, "To send invites you need set `invites_enabled` option to true."}
+ )
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 ea0c92502..32fe69d19 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -625,6 +625,39 @@ test "it returns 403 if requested by a non-admin" do
assert json_response(conn, :forbidden)
end
+
+ test "email with +", %{conn: conn, admin: admin} do
+ recipient_email = "foo+bar@baz.com"
+
+ conn
+ |> put_req_header("content-type", "application/json;charset=utf-8")
+ |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
+ |> json_response(:no_content)
+
+ token_record =
+ Pleroma.UserInviteToken
+ |> Repo.all()
+ |> List.last()
+
+ assert token_record
+ refute token_record.used
+
+ notify_email = Config.get([:instance, :notify_email])
+ instance_name = Config.get([:instance, :name])
+
+ email =
+ Pleroma.Emails.UserEmail.user_invitation_email(
+ admin,
+ token_record,
+ recipient_email
+ )
+
+ Swoosh.TestAssertions.assert_email_sent(
+ from: {instance_name, notify_email},
+ to: recipient_email,
+ html_body: email.html_body
+ )
+ end
end
describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
@@ -637,7 +670,8 @@ test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
- assert json_response(conn, :internal_server_error)
+ assert json_response(conn, :bad_request) ==
+ "To send invites you need set `invites_enabled` option to true."
end
test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
@@ -646,7 +680,8 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
- assert json_response(conn, :internal_server_error)
+ assert json_response(conn, :bad_request) ==
+ "To send invites you need set `registrations_open` option to false."
end
end
From 23219e6fb3163bfac07fb5fb1b2602dcd27e47c2 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Wed, 1 Apr 2020 23:00:59 +0400
Subject: [PATCH 52/85] Add OpenAPI
---
lib/pleroma/web/api_spec.ex | 30 ++++++
.../web/api_spec/operations/app_operation.ex | 94 +++++++++++++++++++
.../api_spec/schemas/app_create_request.ex | 33 +++++++
.../api_spec/schemas/app_create_response.ex | 33 +++++++
.../controllers/app_controller.ex | 9 +-
lib/pleroma/web/oauth/scopes.ex | 7 +-
lib/pleroma/web/router.ex | 11 +++
mix.exs | 3 +-
mix.lock | 1 +
test/web/api_spec/app_operation_test.exs | 45 +++++++++
.../controllers/account_controller_test.exs | 4 +-
.../controllers/app_controller_test.exs | 4 +-
12 files changed, 266 insertions(+), 8 deletions(-)
create mode 100644 lib/pleroma/web/api_spec.ex
create mode 100644 lib/pleroma/web/api_spec/operations/app_operation.ex
create mode 100644 lib/pleroma/web/api_spec/schemas/app_create_request.ex
create mode 100644 lib/pleroma/web/api_spec/schemas/app_create_response.ex
create mode 100644 test/web/api_spec/app_operation_test.exs
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
new file mode 100644
index 000000000..22f76d4bf
--- /dev/null
+++ b/lib/pleroma/web/api_spec.ex
@@ -0,0 +1,30 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec do
+ alias OpenApiSpex.OpenApi
+ alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.Router
+
+ @behaviour OpenApi
+
+ @impl OpenApi
+ def spec do
+ %OpenApi{
+ servers: [
+ # Populate the Server info from a phoenix endpoint
+ OpenApiSpex.Server.from_endpoint(Endpoint)
+ ],
+ info: %OpenApiSpex.Info{
+ title: "Pleroma",
+ description: Application.spec(:pleroma, :description) |> to_string(),
+ version: Application.spec(:pleroma, :vsn) |> to_string()
+ },
+ # populate the paths from a phoenix router
+ paths: OpenApiSpex.Paths.from_router(Router)
+ }
+ # discover request/response schemas from path specs
+ |> OpenApiSpex.resolve_schema_modules()
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/app_operation.ex b/lib/pleroma/web/api_spec/operations/app_operation.ex
new file mode 100644
index 000000000..2a4958acf
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/app_operation.ex
@@ -0,0 +1,94 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.AppOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.AppCreateRequest
+ alias Pleroma.Web.ApiSpec.Schemas.AppCreateResponse
+
+ @spec open_api_operation(atom) :: Operation.t()
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ @spec create_operation() :: Operation.t()
+ def create_operation do
+ %Operation{
+ tags: ["apps"],
+ summary: "Create an application",
+ description: "Create a new application to obtain OAuth2 credentials",
+ operationId: "AppController.create",
+ requestBody:
+ Operation.request_body("Parameters", "application/json", AppCreateRequest, required: true),
+ responses: %{
+ 200 => Operation.response("App", "application/json", AppCreateResponse),
+ 422 =>
+ Operation.response(
+ "Unprocessable Entity",
+ "application/json",
+ %Schema{
+ type: :object,
+ description:
+ "If a required parameter is missing or improperly formatted, the request will fail.",
+ properties: %{
+ error: %Schema{type: :string}
+ },
+ example: %{
+ "error" => "Validation failed: Redirect URI must be an absolute URI."
+ }
+ }
+ )
+ }
+ }
+ end
+
+ def verify_credentials_operation do
+ %Operation{
+ tags: ["apps"],
+ summary: "Verify your app works",
+ description: "Confirm that the app's OAuth2 credentials work.",
+ operationId: "AppController.verify_credentials",
+ parameters: [
+ Operation.parameter(:authorization, :header, :string, "Bearer ", required: true)
+ ],
+ responses: %{
+ 200 =>
+ Operation.response("App", "application/json", %Schema{
+ type: :object,
+ description:
+ "If the Authorization header was provided with a valid token, you should see your app returned as an Application entity.",
+ properties: %{
+ name: %Schema{type: :string},
+ vapid_key: %Schema{type: :string},
+ website: %Schema{type: :string, nullable: true}
+ },
+ example: %{
+ "name" => "My App",
+ "vapid_key" =>
+ "BCk-QqERU0q-CfYZjcuB6lnyyOYfJ2AifKqfeGIm7Z-HiTU5T9eTG5GxVA0_OH5mMlI4UkkDTpaZwozy0TzdZ2M=",
+ "website" => "https://myapp.com/"
+ }
+ }),
+ 422 =>
+ Operation.response(
+ "Unauthorized",
+ "application/json",
+ %Schema{
+ type: :object,
+ description:
+ "If the Authorization header contains an invalid token, is malformed, or is not present, an error will be returned indicating an authorization failure.",
+ properties: %{
+ error: %Schema{type: :string}
+ },
+ example: %{
+ "error" => "The access token is invalid."
+ }
+ }
+ )
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/schemas/app_create_request.ex b/lib/pleroma/web/api_spec/schemas/app_create_request.ex
new file mode 100644
index 000000000..8a83abef3
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/app_create_request.ex
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.AppCreateRequest do
+ alias OpenApiSpex.Schema
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "AppCreateRequest",
+ description: "POST body for creating an app",
+ type: :object,
+ properties: %{
+ client_name: %Schema{type: :string, description: "A name for your application."},
+ redirect_uris: %Schema{
+ type: :string,
+ description:
+ "Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
+ },
+ scopes: %Schema{
+ type: :string,
+ description: "Space separated list of scopes. If none is provided, defaults to `read`."
+ },
+ website: %Schema{type: :string, description: "A URL to the homepage of your app"}
+ },
+ required: [:client_name, :redirect_uris],
+ example: %{
+ "client_name" => "My App",
+ "redirect_uris" => "https://myapp.com/auth/callback",
+ "website" => "https://myapp.com/"
+ }
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/app_create_response.ex b/lib/pleroma/web/api_spec/schemas/app_create_response.ex
new file mode 100644
index 000000000..f290fb031
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/app_create_response.ex
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.AppCreateResponse do
+ alias OpenApiSpex.Schema
+
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "AppCreateResponse",
+ description: "Response schema for an app",
+ type: :object,
+ properties: %{
+ id: %Schema{type: :string},
+ name: %Schema{type: :string},
+ client_id: %Schema{type: :string},
+ client_secret: %Schema{type: :string},
+ redirect_uri: %Schema{type: :string},
+ vapid_key: %Schema{type: :string},
+ website: %Schema{type: :string, nullable: true}
+ },
+ example: %{
+ "id" => "123",
+ "name" => "My App",
+ "client_id" => "TWhM-tNSuncnqN7DBJmoyeLnk6K3iJJ71KKXxgL1hPM",
+ "client_secret" => "ZEaFUFmF0umgBX1qKJDjaU99Q31lDkOU8NutzTOoliw",
+ "vapid_key" =>
+ "BCk-QqERU0q-CfYZjcuB6lnyyOYfJ2AifKqfeGIm7Z-HiTU5T9eTG5GxVA0_OH5mMlI4UkkDTpaZwozy0TzdZ2M=",
+ "website" => "https://myapp.com/"
+ }
+ })
+end
diff --git a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
index 5e2871f18..005c60444 100644
--- a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
@@ -14,17 +14,20 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
plug(OAuthScopesPlug, %{scopes: ["read"]} when action == :verify_credentials)
+ plug(OpenApiSpex.Plug.CastAndValidate)
@local_mastodon_name "Mastodon-Local"
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.AppOperation
+
@doc "POST /api/v1/apps"
- def create(conn, params) do
+ def create(%{body_params: params} = conn, _params) do
scopes = Scopes.fetch_scopes(params, ["read"])
app_attrs =
params
- |> Map.drop(["scope", "scopes"])
- |> Map.put("scopes", scopes)
+ |> Map.take([:client_name, :redirect_uris, :website])
+ |> Map.put(:scopes, scopes)
with cs <- App.register_changeset(%App{}, app_attrs),
false <- cs.changes[:client_name] == @local_mastodon_name,
diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex
index 8ecf901f3..1023f16d4 100644
--- a/lib/pleroma/web/oauth/scopes.ex
+++ b/lib/pleroma/web/oauth/scopes.ex
@@ -15,7 +15,12 @@ defmodule Pleroma.Web.OAuth.Scopes do
Note: `scopes` is used by Mastodon — supporting it but sticking to
OAuth's standard `scope` wherever we control it
"""
- @spec fetch_scopes(map(), list()) :: list()
+ @spec fetch_scopes(map() | struct(), list()) :: list()
+
+ def fetch_scopes(%Pleroma.Web.ApiSpec.Schemas.AppCreateRequest{scopes: scopes}, default) do
+ parse_scopes(scopes, default)
+ end
+
def fetch_scopes(params, default) do
parse_scopes(params["scope"] || params["scopes"], default)
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 5a0902739..3ecd59cd1 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -29,6 +29,7 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Plugs.SetUserSessionIdPlug)
plug(Pleroma.Plugs.EnsureUserKeyPlug)
plug(Pleroma.Plugs.IdempotencyPlug)
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :authenticated_api do
@@ -44,6 +45,7 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Plugs.SetUserSessionIdPlug)
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
plug(Pleroma.Plugs.IdempotencyPlug)
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :admin_api do
@@ -61,6 +63,7 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
plug(Pleroma.Plugs.UserIsAdminPlug)
plug(Pleroma.Plugs.IdempotencyPlug)
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :mastodon_html do
@@ -94,10 +97,12 @@ defmodule Pleroma.Web.Router do
pipeline :config do
plug(:accepts, ["json", "xml"])
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :pleroma_api do
plug(:accepts, ["html", "json"])
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :mailbox_preview do
@@ -500,6 +505,12 @@ defmodule Pleroma.Web.Router do
)
end
+ scope "/api" do
+ pipe_through(:api)
+
+ get("/openapi", OpenApiSpex.Plug.RenderSpec, [])
+ end
+
scope "/api", Pleroma.Web, as: :authenticated_twitter_api do
pipe_through(:authenticated_api)
diff --git a/mix.exs b/mix.exs
index 890979f8b..ebd4a5ea6 100644
--- a/mix.exs
+++ b/mix.exs
@@ -171,7 +171,8 @@ defp deps do
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
{:mox, "~> 0.5", only: :test},
- {:restarter, path: "./restarter"}
+ {:restarter, path: "./restarter"},
+ {:open_api_spex, "~> 3.6"}
] ++ oauth_deps()
end
diff --git a/mix.lock b/mix.lock
index 62e14924a..fd26ca01b 100644
--- a/mix.lock
+++ b/mix.lock
@@ -72,6 +72,7 @@
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
"oban": {:hex, :oban, "0.12.1", "695e9490c6e0edfca616d80639528e448bd29b3bff7b7dd10a56c79b00a5d7fb", [: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", "c1d58d69b8b5a86e7167abbb8cc92764a66f25f12f6172052595067fc6a30a17"},
+ "open_api_spex": {:hex, :open_api_spex, "3.6.0", "64205aba9f2607f71b08fd43e3351b9c5e9898ec5ef49fc0ae35890da502ade9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "126ba3473966277132079cb1d5bf1e3df9e36fe2acd00166e75fd125cecb59c5"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm", "595d09db74cb093b1903381c9de423276a931a2480a46a1a5dc7f932a2a6375b"},
"phoenix": {:hex, :phoenix, "1.4.13", "67271ad69b51f3719354604f4a3f968f83aa61c19199343656c9caee057ff3b8", [: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", "ab765a0feddb81fc62e2116c827b5f068df85159c162bee760745276ad7ddc1b"},
diff --git a/test/web/api_spec/app_operation_test.exs b/test/web/api_spec/app_operation_test.exs
new file mode 100644
index 000000000..5b96abb44
--- /dev/null
+++ b/test/web/api_spec/app_operation_test.exs
@@ -0,0 +1,45 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.AppOperationTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ alias Pleroma.Web.ApiSpec
+ alias Pleroma.Web.ApiSpec.Schemas.AppCreateRequest
+ alias Pleroma.Web.ApiSpec.Schemas.AppCreateResponse
+
+ import OpenApiSpex.TestAssertions
+ import Pleroma.Factory
+
+ test "AppCreateRequest example matches schema" do
+ api_spec = ApiSpec.spec()
+ schema = AppCreateRequest.schema()
+ assert_schema(schema.example, "AppCreateRequest", api_spec)
+ end
+
+ test "AppCreateResponse example matches schema" do
+ api_spec = ApiSpec.spec()
+ schema = AppCreateResponse.schema()
+ assert_schema(schema.example, "AppCreateResponse", api_spec)
+ end
+
+ test "AppController produces a AppCreateResponse", %{conn: conn} do
+ api_spec = ApiSpec.spec()
+ app_attrs = build(:oauth_app)
+
+ json =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post(
+ "/api/v1/apps",
+ Jason.encode!(%{
+ client_name: app_attrs.client_name,
+ redirect_uris: app_attrs.redirect_uris
+ })
+ )
+ |> json_response(200)
+
+ assert_schema(json, "AppCreateResponse", api_spec)
+ end
+end
diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs
index a9fa0ce48..a450a732c 100644
--- a/test/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/web/mastodon_api/controllers/account_controller_test.exs
@@ -794,7 +794,9 @@ test "blocking / unblocking a user" do
test "Account registration via Application", %{conn: conn} do
conn =
- post(conn, "/api/v1/apps", %{
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/apps", %{
client_name: "client_name",
redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
scopes: "read, write, follow"
diff --git a/test/web/mastodon_api/controllers/app_controller_test.exs b/test/web/mastodon_api/controllers/app_controller_test.exs
index 77d234d67..e7b11d14e 100644
--- a/test/web/mastodon_api/controllers/app_controller_test.exs
+++ b/test/web/mastodon_api/controllers/app_controller_test.exs
@@ -16,8 +16,7 @@ test "apps/verify_credentials", %{conn: conn} do
conn =
conn
- |> assign(:user, token.user)
- |> assign(:token, token)
+ |> put_req_header("authorization", "Bearer #{token.token}")
|> get("/api/v1/apps/verify_credentials")
app = Repo.preload(token, :app).app
@@ -37,6 +36,7 @@ test "creates an oauth app", %{conn: conn} do
conn =
conn
+ |> put_req_header("content-type", "application/json")
|> assign(:user, user)
|> post("/api/v1/apps", %{
client_name: app_attrs.client_name,
From 591f7015d91b383dae1ee29576d13c0fad65cad6 Mon Sep 17 00:00:00 2001
From: Maksim Pechnikov
Date: Thu, 2 Apr 2020 09:34:11 +0300
Subject: [PATCH 53/85] update Oban package
---
mix.exs | 2 +-
mix.lock | 6 +++---
.../20200402063221_update_oban_jobs_table.exs | 11 +++++++++++
3 files changed, 15 insertions(+), 4 deletions(-)
create mode 100644 priv/repo/migrations/20200402063221_update_oban_jobs_table.exs
diff --git a/mix.exs b/mix.exs
index 87c025d89..375bc67c1 100644
--- a/mix.exs
+++ b/mix.exs
@@ -108,7 +108,7 @@ defp deps do
{:ecto_enum, "~> 1.4"},
{:ecto_sql, "~> 3.3.2"},
{:postgrex, ">= 0.13.5"},
- {:oban, "~> 0.12.1"},
+ {:oban, "~> 1.2"},
{:gettext, "~> 0.15"},
{:comeonin, "~> 4.1.1"},
{:pbkdf2_elixir, "~> 0.12.3"},
diff --git a/mix.lock b/mix.lock
index 6cca578d6..50be45a4d 100644
--- a/mix.lock
+++ b/mix.lock
@@ -26,7 +26,7 @@
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
- "ecto": {:hex, :ecto, "3.3.3", "0830bf3aebcbf3d8c1a1811cd581773b6866886c012f52c0f027031fa96a0b53", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "12e368e3c2a2938d7776defaabdae40e82900fc4d8d66120ec1e01dfd8b93c3a"},
+ "ecto": {:hex, :ecto, "3.4.0", "a7a83ab8359bf816ce729e5e65981ce25b9fc5adfc89c2ea3980f4fed0bfd7c1", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "5eed18252f5b5bbadec56a24112b531343507dbe046273133176b12190ce19cc"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.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", "5eccbdbf92e3c6f213007a82d5dbba4cd9bb659d1a21331f89f408e4c0efd7a8"},
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
@@ -55,7 +55,7 @@
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
- "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"},
+ "jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"},
"joken": {:hex, :joken, "2.2.0", "2daa1b12be05184aff7b5ace1d43ca1f81345962285fff3f88db74927c954d3a", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "b4f92e30388206f869dd25d1af628a1d99d7586e5cf0672f64d4df84c4d2f5e9"},
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
@@ -73,7 +73,7 @@
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
- "oban": {:hex, :oban, "0.12.1", "695e9490c6e0edfca616d80639528e448bd29b3bff7b7dd10a56c79b00a5d7fb", [: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", "c1d58d69b8b5a86e7167abbb8cc92764a66f25f12f6172052595067fc6a30a17"},
+ "oban": {:hex, :oban, "1.2.0", "7cca94d341be43d220571e28f69131c4afc21095b25257397f50973d3fc59b07", [: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", "ba5f8b3f7d76967b3e23cf8014f6a13e4ccb33431e4808f036709a7f822362ee"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm", "595d09db74cb093b1903381c9de423276a931a2480a46a1a5dc7f932a2a6375b"},
"phoenix": {:hex, :phoenix, "1.4.13", "67271ad69b51f3719354604f4a3f968f83aa61c19199343656c9caee057ff3b8", [: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", "ab765a0feddb81fc62e2116c827b5f068df85159c162bee760745276ad7ddc1b"},
diff --git a/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs b/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs
new file mode 100644
index 000000000..c8ee12192
--- /dev/null
+++ b/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs
@@ -0,0 +1,11 @@
+defmodule Pleroma.Repo.Migrations.UpdateObanJobsTable do
+ use Ecto.Migration
+
+ def up do
+ Oban.Migrations.up()
+ end
+
+ def down do
+ Oban.Migrations.down(version: 1)
+ end
+end
From 0aa24a150bbb153f55ca92dfb595385b4fe3839c Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Thu, 2 Apr 2020 17:33:23 +0400
Subject: [PATCH 54/85] Add oAuth
---
lib/pleroma/web/api_spec.ex | 16 +++++++++++++++-
.../web/api_spec/operations/app_operation.ex | 6 ++++--
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
index 22f76d4bf..41e48a085 100644
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -22,7 +22,21 @@ def spec do
version: Application.spec(:pleroma, :vsn) |> to_string()
},
# populate the paths from a phoenix router
- paths: OpenApiSpex.Paths.from_router(Router)
+ paths: OpenApiSpex.Paths.from_router(Router),
+ components: %OpenApiSpex.Components{
+ securitySchemes: %{
+ "oAuth" => %OpenApiSpex.SecurityScheme{
+ type: "oauth2",
+ flows: %OpenApiSpex.OAuthFlows{
+ password: %OpenApiSpex.OAuthFlow{
+ authorizationUrl: "/oauth/authorize",
+ tokenUrl: "/oauth/token",
+ scopes: %{"read" => "read"}
+ }
+ }
+ }
+ }
+ }
}
# discover request/response schemas from path specs
|> OpenApiSpex.resolve_schema_modules()
diff --git a/lib/pleroma/web/api_spec/operations/app_operation.ex b/lib/pleroma/web/api_spec/operations/app_operation.ex
index 2a4958acf..41d56693a 100644
--- a/lib/pleroma/web/api_spec/operations/app_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/app_operation.ex
@@ -51,8 +51,10 @@ def verify_credentials_operation do
summary: "Verify your app works",
description: "Confirm that the app's OAuth2 credentials work.",
operationId: "AppController.verify_credentials",
- parameters: [
- Operation.parameter(:authorization, :header, :string, "Bearer ", required: true)
+ security: [
+ %{
+ "oAuth" => ["read"]
+ }
],
responses: %{
200 =>
From 8a0ffaa9ead2574707cb45c014cb421ff31f7a03 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Thu, 2 Apr 2020 23:01:29 +0400
Subject: [PATCH 55/85] Fix formatting in documentation
---
docs/API/differences_in_mastoapi_responses.md | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md
index dc8f54d2a..1059155cf 100644
--- a/docs/API/differences_in_mastoapi_responses.md
+++ b/docs/API/differences_in_mastoapi_responses.md
@@ -164,6 +164,7 @@ Additional parameters can be added to the JSON body/Form data:
- `actor_type` - the type of this account.
### Pleroma Settings Store
+
Pleroma has mechanism that allows frontends to save blobs of json for each user on the backend. This can be used to save frontend-specific settings for a user that the backend does not need to know about.
The parameter should have a form of `{frontend_name: {...}}`, with `frontend_name` identifying your type of client, e.g. `pleroma_fe`. It will overwrite everything under this property, but will not overwrite other frontend's settings.
@@ -172,17 +173,20 @@ This information is returned in the `verify_credentials` endpoint.
## Authentication
-*Pleroma supports refreshing tokens.
+*Pleroma supports refreshing tokens.*
`POST /oauth/token`
-Post here request with grant_type=refresh_token to obtain new access token. Returns an access token.
+
+Post here request with `grant_type=refresh_token` to obtain new access token. Returns an access token.
## Account Registration
+
`POST /api/v1/accounts`
Has theses additional parameters (which are the same as in Pleroma-API):
- * `fullname`: optional
- * `bio`: optional
- * `captcha_solution`: optional, contains provider-specific captcha solution,
- * `captcha_token`: optional, contains provider-specific captcha token
- * `token`: invite token required when the registerations aren't public.
+
+- `fullname`: optional
+- `bio`: optional
+- `captcha_solution`: optional, contains provider-specific captcha solution,
+- `captcha_token`: optional, contains provider-specific captcha token
+- `token`: invite token required when the registrations aren't public.
From b59ac37b2c09d5dc80b59bd3a2aea36989bee713 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Mon, 6 Apr 2020 10:45:25 +0300
Subject: [PATCH 56/85] tests for emoji mix task
---
coveralls.json | 6 +
docs/administration/CLI_tasks/emoji.md | 4 +-
lib/mix/tasks/pleroma/emoji.ex | 90 ++++---
test/fixtures/emoji/packs/blank.png.zip | Bin 0 -> 284 bytes
.../emoji/packs/default-manifest.json | 10 +
test/fixtures/emoji/packs/finmoji.json | 3 +
test/fixtures/emoji/packs/manifest.json | 10 +
test/tasks/emoji_test.exs | 226 ++++++++++++++++++
8 files changed, 311 insertions(+), 38 deletions(-)
create mode 100644 coveralls.json
create mode 100644 test/fixtures/emoji/packs/blank.png.zip
create mode 100644 test/fixtures/emoji/packs/default-manifest.json
create mode 100644 test/fixtures/emoji/packs/finmoji.json
create mode 100644 test/fixtures/emoji/packs/manifest.json
create mode 100644 test/tasks/emoji_test.exs
diff --git a/coveralls.json b/coveralls.json
new file mode 100644
index 000000000..75e845ade
--- /dev/null
+++ b/coveralls.json
@@ -0,0 +1,6 @@
+{
+ "skip_files": [
+ "test/support",
+ "lib/mix/tasks/pleroma/benchmark.ex"
+ ]
+}
\ No newline at end of file
diff --git a/docs/administration/CLI_tasks/emoji.md b/docs/administration/CLI_tasks/emoji.md
index efec8222c..3d524a52b 100644
--- a/docs/administration/CLI_tasks/emoji.md
+++ b/docs/administration/CLI_tasks/emoji.md
@@ -39,8 +39,8 @@ mix pleroma.emoji get-packs [option ...]
mix pleroma.emoji gen-pack PACK-URL
```
-Currently, only .zip archives are recognized as remote pack files and packs are therefore assumed to be zip archives. This command is intended to run interactively and will first ask you some basic questions about the pack, then download the remote file and generate an SHA256 checksum for it, then generate an emoji file list for you.
+Currently, only .zip archives are recognized as remote pack files and packs are therefore assumed to be zip archives. This command is intended to run interactively and will first ask you some basic questions about the pack, then download the remote file and generate an SHA256 checksum for it, then generate an emoji file list for you.
- The manifest entry will either be written to a newly created `index.json` file or appended to the existing one, *replacing* the old pack with the same name if it was in the file previously.
+ The manifest entry will either be written to a newly created `pack_name.json` file (pack name is asked in questions) or appended to the existing one, *replacing* the old pack with the same name if it was in the file previously.
The file list will be written to the file specified previously, *replacing* that file. You _should_ check that the file list doesn't contain anything you don't need in the pack, that is, anything that is not an emoji (the whole pack is downloaded, but only emoji files are extracted).
diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex
index 429d763c7..cdffa88b2 100644
--- a/lib/mix/tasks/pleroma/emoji.ex
+++ b/lib/mix/tasks/pleroma/emoji.ex
@@ -14,8 +14,8 @@ def run(["ls-packs" | args]) do
{options, [], []} = parse_global_opts(args)
- manifest =
- fetch_manifest(if options[:manifest], do: options[:manifest], else: default_manifest())
+ url_or_path = options[:manifest] || default_manifest()
+ manifest = fetch_manifest(url_or_path)
Enum.each(manifest, fn {name, info} ->
to_print = [
@@ -40,9 +40,9 @@ def run(["get-packs" | args]) do
{options, pack_names, []} = parse_global_opts(args)
- manifest_url = if options[:manifest], do: options[:manifest], else: default_manifest()
+ url_or_path = options[:manifest] || default_manifest()
- manifest = fetch_manifest(manifest_url)
+ manifest = fetch_manifest(url_or_path)
for pack_name <- pack_names do
if Map.has_key?(manifest, pack_name) do
@@ -75,7 +75,10 @@ def run(["get-packs" | args]) do
end
# The url specified in files should be in the same directory
- files_url = Path.join(Path.dirname(manifest_url), pack["files"])
+ files_url =
+ url_or_path
+ |> Path.dirname()
+ |> Path.join(pack["files"])
IO.puts(
IO.ANSI.format([
@@ -133,38 +136,51 @@ def run(["get-packs" | args]) do
end
end
- def run(["gen-pack", src]) do
+ def run(["gen-pack" | args]) do
start_pleroma()
- proposed_name = Path.basename(src) |> Path.rootname()
- name = String.trim(IO.gets("Pack name [#{proposed_name}]: "))
- # If there's no name, use the default one
- name = if String.length(name) > 0, do: name, else: proposed_name
-
- license = String.trim(IO.gets("License: "))
- homepage = String.trim(IO.gets("Homepage: "))
- description = String.trim(IO.gets("Description: "))
-
- proposed_files_name = "#{name}.json"
- files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: "))
- files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name
-
- default_exts = [".png", ".gif"]
- default_exts_str = Enum.join(default_exts, " ")
-
- exts =
- String.trim(
- IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ")
+ {opts, [src], []} =
+ OptionParser.parse(
+ args,
+ strict: [
+ name: :string,
+ license: :string,
+ homepage: :string,
+ description: :string,
+ files: :string,
+ extensions: :string
+ ]
)
+ proposed_name = Path.basename(src) |> Path.rootname()
+ name = get_option(opts, :name, "Pack name:", proposed_name)
+ license = get_option(opts, :license, "License:")
+ homepage = get_option(opts, :homepage, "Homepage:")
+ description = get_option(opts, :description, "Description:")
+
+ proposed_files_name = "#{name}_files.json"
+ files_name = get_option(opts, :files, "Save file list to:", proposed_files_name)
+
+ default_exts = [".png", ".gif"]
+
+ custom_exts =
+ get_option(
+ opts,
+ :extensions,
+ "Emoji file extensions (separated with spaces):",
+ Enum.join(default_exts, " ")
+ )
+ |> String.split(" ", trim: true)
+
exts =
- if String.length(exts) > 0 do
- String.split(exts, " ")
- |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end)
- else
+ if MapSet.equal?(MapSet.new(default_exts), MapSet.new(custom_exts)) do
default_exts
+ else
+ custom_exts
end
+ IO.puts("Using #{Enum.join(exts, " ")} extensions")
+
IO.puts("Downloading the pack and generating SHA256")
binary_archive = Tesla.get!(client(), src).body
@@ -194,14 +210,16 @@ def run(["gen-pack", src]) do
IO.puts("""
#{files_name} has been created and contains the list of all found emojis in the pack.
- Please review the files in the remove those not needed.
+ Please review the files in the pack and remove those not needed.
""")
- if File.exists?("index.json") do
- existing_data = File.read!("index.json") |> Jason.decode!()
+ pack_file = "#{name}.json"
+
+ if File.exists?(pack_file) do
+ existing_data = File.read!(pack_file) |> Jason.decode!()
File.write!(
- "index.json",
+ pack_file,
Jason.encode!(
Map.merge(
existing_data,
@@ -211,11 +229,11 @@ def run(["gen-pack", src]) do
)
)
- IO.puts("index.json file has been update with the #{name} pack")
+ IO.puts("#{pack_file} has been updated with the #{name} pack")
else
- File.write!("index.json", Jason.encode!(pack_json, pretty: true))
+ File.write!(pack_file, Jason.encode!(pack_json, pretty: true))
- IO.puts("index.json has been created with the #{name} pack")
+ IO.puts("#{pack_file} has been created with the #{name} pack")
end
end
diff --git a/test/fixtures/emoji/packs/blank.png.zip b/test/fixtures/emoji/packs/blank.png.zip
new file mode 100644
index 0000000000000000000000000000000000000000..651daf1271fb95ca1404142441360eed4fbdd45d
GIT binary patch
literal 284
zcmWIWW@Zs#-~d9a?B)OlD2NBroD2#KNjZsm*?I+e>7gOK4D5#d?QteR45CXbxEUB(
zzA`c}0JSqPyyp2({QT*pM@b0@559gW;AFbQt8j)xMIvtZu_cU}%O)x8Phe}?bTVDH
z!G_ac{P+Z}V^3I*39acCcBz`h#Jl4TUzUMEfr)`Z-T9eS0!uDmzIr}&Zm^RuLx49s
yM|^mrXavv>kfQ>;8JR?w5e`O{134H5mNbG`L_0sgo0Scufe{G9f%JM1hXDXq!$&v(
literal 0
HcmV?d00001
diff --git a/test/fixtures/emoji/packs/default-manifest.json b/test/fixtures/emoji/packs/default-manifest.json
new file mode 100644
index 000000000..c8433808d
--- /dev/null
+++ b/test/fixtures/emoji/packs/default-manifest.json
@@ -0,0 +1,10 @@
+{
+ "finmoji": {
+ "license": "CC BY-NC-ND 4.0",
+ "homepage": "https://finland.fi/emoji/",
+ "description": "Finland is the first country in the world to publish its own set of country themed emojis. The Finland emoji collection contains 56 tongue-in-cheek emotions, which were created to explain some hard-to-describe Finnish emotions, Finnish words and customs.",
+ "src": "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip",
+ "src_sha256": "384025A1AC6314473863A11AC7AB38A12C01B851A3F82359B89B4D4211D3291D",
+ "files": "finmoji.json"
+ }
+}
\ No newline at end of file
diff --git a/test/fixtures/emoji/packs/finmoji.json b/test/fixtures/emoji/packs/finmoji.json
new file mode 100644
index 000000000..279770998
--- /dev/null
+++ b/test/fixtures/emoji/packs/finmoji.json
@@ -0,0 +1,3 @@
+{
+ "blank": "blank.png"
+}
\ No newline at end of file
diff --git a/test/fixtures/emoji/packs/manifest.json b/test/fixtures/emoji/packs/manifest.json
new file mode 100644
index 000000000..2d51a459b
--- /dev/null
+++ b/test/fixtures/emoji/packs/manifest.json
@@ -0,0 +1,10 @@
+{
+ "blobs.gg": {
+ "src_sha256": "3a12f3a181678d5b3584a62095411b0d60a335118135910d879920f8ade5a57f",
+ "src": "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip",
+ "license": "Apache 2.0",
+ "homepage": "https://blobs.gg",
+ "files": "blobs_gg.json",
+ "description": "Blob Emoji from blobs.gg repacked as apng"
+ }
+}
\ No newline at end of file
diff --git a/test/tasks/emoji_test.exs b/test/tasks/emoji_test.exs
new file mode 100644
index 000000000..f2930652a
--- /dev/null
+++ b/test/tasks/emoji_test.exs
@@ -0,0 +1,226 @@
+defmodule Mix.Tasks.Pleroma.EmojiTest do
+ use ExUnit.Case, async: true
+
+ import ExUnit.CaptureIO
+ import Tesla.Mock
+
+ alias Mix.Tasks.Pleroma.Emoji
+
+ describe "ls-packs" do
+ test "with default manifest as url" do
+ mock(fn
+ %{
+ method: :get,
+ url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/emoji/packs/default-manifest.json")
+ }
+ end)
+
+ capture_io(fn -> Emoji.run(["ls-packs"]) end) =~
+ "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip"
+ end
+
+ test "with passed manifest as file" do
+ capture_io(fn ->
+ Emoji.run(["ls-packs", "-m", "test/fixtures/emoji/packs/manifest.json"])
+ end) =~ "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip"
+ end
+ end
+
+ describe "get-packs" do
+ test "download pack from default manifest" do
+ mock(fn
+ %{
+ method: :get,
+ url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/emoji/packs/default-manifest.json")
+ }
+
+ %{
+ method: :get,
+ url: "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/emoji/packs/blank.png.zip")
+ }
+
+ %{
+ method: :get,
+ url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/finmoji.json"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/emoji/packs/finmoji.json")
+ }
+ end)
+
+ assert capture_io(fn -> Emoji.run(["get-packs", "finmoji"]) end) =~ "Writing pack.json for"
+
+ emoji_path =
+ Path.join(
+ Pleroma.Config.get!([:instance, :static_dir]),
+ "emoji"
+ )
+
+ assert File.exists?(Path.join([emoji_path, "finmoji", "pack.json"]))
+ on_exit(fn -> File.rm_rf!("test/instance_static/emoji/finmoji") end)
+ end
+
+ test "pack not found" do
+ mock(fn
+ %{
+ method: :get,
+ url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/emoji/packs/default-manifest.json")
+ }
+ end)
+
+ assert capture_io(fn -> Emoji.run(["get-packs", "not_found"]) end) =~
+ "No pack named \"not_found\" found"
+ end
+
+ test "raise on bad sha256" do
+ mock(fn
+ %{
+ method: :get,
+ url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/emoji/packs/blank.png.zip")
+ }
+ end)
+
+ assert_raise RuntimeError, ~r/^Bad SHA256 for blobs.gg/, fn ->
+ capture_io(fn ->
+ Emoji.run(["get-packs", "blobs.gg", "-m", "test/fixtures/emoji/packs/manifest.json"])
+ end)
+ end
+ end
+ end
+
+ describe "gen-pack" do
+ setup do
+ url = "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip"
+
+ mock(fn %{
+ method: :get,
+ url: ^url
+ } ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/emoji/packs/blank.png.zip")}
+ end)
+
+ {:ok, url: url}
+ end
+
+ test "with default extensions", %{url: url} do
+ name = "pack1"
+ pack_json = "#{name}.json"
+ files_json = "#{name}_file.json"
+ refute File.exists?(pack_json)
+ refute File.exists?(files_json)
+
+ captured =
+ capture_io(fn ->
+ Emoji.run([
+ "gen-pack",
+ url,
+ "--name",
+ name,
+ "--license",
+ "license",
+ "--homepage",
+ "homepage",
+ "--description",
+ "description",
+ "--files",
+ files_json,
+ "--extensions",
+ ".png .gif"
+ ])
+ end)
+
+ assert captured =~ "#{pack_json} has been created with the pack1 pack"
+ assert captured =~ "Using .png .gif extensions"
+
+ assert File.exists?(pack_json)
+ assert File.exists?(files_json)
+
+ on_exit(fn ->
+ File.rm_rf!(pack_json)
+ File.rm_rf!(files_json)
+ end)
+ end
+
+ test "with custom extensions and update existing files", %{url: url} do
+ name = "pack2"
+ pack_json = "#{name}.json"
+ files_json = "#{name}_file.json"
+ refute File.exists?(pack_json)
+ refute File.exists?(files_json)
+
+ captured =
+ capture_io(fn ->
+ Emoji.run([
+ "gen-pack",
+ url,
+ "--name",
+ name,
+ "--license",
+ "license",
+ "--homepage",
+ "homepage",
+ "--description",
+ "description",
+ "--files",
+ files_json,
+ "--extensions",
+ " .png .gif .jpeg "
+ ])
+ end)
+
+ assert captured =~ "#{pack_json} has been created with the pack2 pack"
+ assert captured =~ "Using .png .gif .jpeg extensions"
+
+ assert File.exists?(pack_json)
+ assert File.exists?(files_json)
+
+ captured =
+ capture_io(fn ->
+ Emoji.run([
+ "gen-pack",
+ url,
+ "--name",
+ name,
+ "--license",
+ "license",
+ "--homepage",
+ "homepage",
+ "--description",
+ "description",
+ "--files",
+ files_json,
+ "--extensions",
+ " .png .gif .jpeg "
+ ])
+ end)
+
+ assert captured =~ "#{pack_json} has been updated with the pack2 pack"
+
+ on_exit(fn ->
+ File.rm_rf!(pack_json)
+ File.rm_rf!(files_json)
+ end)
+ end
+ end
+end
From a43e05591639132ce121d2e14258944a53004438 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Mon, 6 Apr 2020 14:27:20 +0300
Subject: [PATCH 57/85] using another fn for file deletion
---
test/tasks/emoji_test.exs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/tasks/emoji_test.exs b/test/tasks/emoji_test.exs
index f2930652a..f5de3ef0e 100644
--- a/test/tasks/emoji_test.exs
+++ b/test/tasks/emoji_test.exs
@@ -157,8 +157,8 @@ test "with default extensions", %{url: url} do
assert File.exists?(files_json)
on_exit(fn ->
- File.rm_rf!(pack_json)
- File.rm_rf!(files_json)
+ File.rm!(pack_json)
+ File.rm!(files_json)
end)
end
@@ -218,8 +218,8 @@ test "with custom extensions and update existing files", %{url: url} do
assert captured =~ "#{pack_json} has been updated with the pack2 pack"
on_exit(fn ->
- File.rm_rf!(pack_json)
- File.rm_rf!(files_json)
+ File.rm!(pack_json)
+ File.rm!(files_json)
end)
end
end
From e67cde0ed6b55450b5f309f9ed86f7f8e2a1e73f Mon Sep 17 00:00:00 2001
From: lain
Date: Mon, 6 Apr 2020 13:46:34 +0200
Subject: [PATCH 58/85] Transmogrifier: Refactoring / Renaming.
---
lib/pleroma/web/activity_pub/transmogrifier.ex | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index a4b385cd5..455f51fe0 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -617,9 +617,9 @@ def handle_incoming(%{"type" => "Like"} = data, _options) do
data |> LikeValidator.cast_data() |> Ecto.Changeset.apply_action(:insert)},
cast_data = ObjectValidator.stringify_keys(Map.from_struct(cast_data_sym)),
:ok <- ObjectValidator.fetch_actor_and_object(cast_data),
- {_, {:ok, cast_data}} <- {:maybe_add_context, maybe_add_context_from_object(cast_data)},
+ {_, {:ok, cast_data}} <- {:ensure_context_presence, ensure_context_presence(cast_data)},
{_, {:ok, cast_data}} <-
- {:maybe_add_recipients, maybe_add_recipients_from_object(cast_data)},
+ {:ensure_recipients_presence, ensure_recipients_presence(cast_data)},
{_, {:ok, activity, _meta}} <-
{:common_pipeline, Pipeline.common_pipeline(cast_data, local: false)} do
{:ok, activity}
@@ -1251,10 +1251,10 @@ def maybe_fix_user_url(data), do: data
def maybe_fix_user_object(data), do: maybe_fix_user_url(data)
- defp maybe_add_context_from_object(%{"context" => context} = data) when is_binary(context),
+ defp ensure_context_presence(%{"context" => context} = data) when is_binary(context),
do: {:ok, data}
- defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(object) do
+ defp ensure_context_presence(%{"object" => object} = data) when is_binary(object) do
with %{data: %{"context" => context}} when is_binary(context) <- Object.normalize(object) do
{:ok, Map.put(data, "context", context)}
else
@@ -1263,14 +1263,14 @@ defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(
end
end
- defp maybe_add_context_from_object(_) do
+ defp ensure_context_presence(_) do
{:error, :no_context}
end
- defp maybe_add_recipients_from_object(%{"to" => [_ | _], "cc" => [_ | _]} = data),
+ defp ensure_recipients_presence(%{"to" => [_ | _], "cc" => [_ | _]} = data),
do: {:ok, data}
- defp maybe_add_recipients_from_object(%{"object" => object} = data) do
+ defp ensure_recipients_presence(%{"object" => object} = data) do
case Object.normalize(object) do
%{data: %{"actor" => actor}} ->
data =
@@ -1288,7 +1288,7 @@ defp maybe_add_recipients_from_object(%{"object" => object} = data) do
end
end
- defp maybe_add_recipients_from_object(_) do
+ defp ensure_recipients_presence(_) do
{:error, :no_object}
end
end
From 772bc258cde11b3203ad9420f69321ccd56db91a Mon Sep 17 00:00:00 2001
From: lain
Date: Mon, 6 Apr 2020 13:53:24 +0200
Subject: [PATCH 59/85] ObjectID Validator: Refactor.
---
.../object_validators/types/object_id.ex | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
index 8e70effe4..ee10be0b0 100644
--- a/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
@@ -4,14 +4,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID do
def type, do: :string
def cast(object) when is_binary(object) do
- with %URI{
- scheme: scheme,
- host: host
- }
- when scheme in ["https", "http"] and not is_nil(host) <-
- URI.parse(object) do
- {:ok, object}
- else
+ # Host has to be present and scheme has to be an http scheme (for now)
+ case URI.parse(object) do
+ %URI{host: nil} ->
+ :error
+
+ %URI{scheme: scheme} when scheme in ["https", "http"] ->
+ {:ok, object}
+
_ ->
:error
end
From 03eebabe8e5b2e3f96f6ffe51a6f063a42f6a5d2 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Fri, 3 Apr 2020 22:52:25 +0400
Subject: [PATCH 60/85] Add Pleroma.Web.ApiSpec.Helpers
---
lib/pleroma/web/api_spec/helpers.ex | 27 +++++++++++++++++++
.../web/api_spec/operations/app_operation.ex | 4 +--
2 files changed, 29 insertions(+), 2 deletions(-)
create mode 100644 lib/pleroma/web/api_spec/helpers.ex
diff --git a/lib/pleroma/web/api_spec/helpers.ex b/lib/pleroma/web/api_spec/helpers.ex
new file mode 100644
index 000000000..35cf4c0d8
--- /dev/null
+++ b/lib/pleroma/web/api_spec/helpers.ex
@@ -0,0 +1,27 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Helpers do
+ def request_body(description, schema_ref, opts \\ []) do
+ media_types = ["application/json", "multipart/form-data"]
+
+ content =
+ media_types
+ |> Enum.map(fn type ->
+ {type,
+ %OpenApiSpex.MediaType{
+ schema: schema_ref,
+ example: opts[:example],
+ examples: opts[:examples]
+ }}
+ end)
+ |> Enum.into(%{})
+
+ %OpenApiSpex.RequestBody{
+ description: description,
+ content: content,
+ required: opts[:required] || false
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/app_operation.ex b/lib/pleroma/web/api_spec/operations/app_operation.ex
index 41d56693a..26d8dbd42 100644
--- a/lib/pleroma/web/api_spec/operations/app_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/app_operation.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.ApiSpec.AppOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.AppCreateRequest
alias Pleroma.Web.ApiSpec.Schemas.AppCreateResponse
@@ -21,8 +22,7 @@ def create_operation do
summary: "Create an application",
description: "Create a new application to obtain OAuth2 credentials",
operationId: "AppController.create",
- requestBody:
- Operation.request_body("Parameters", "application/json", AppCreateRequest, required: true),
+ requestBody: Helpers.request_body("Parameters", AppCreateRequest, required: true),
responses: %{
200 => Operation.response("App", "application/json", AppCreateResponse),
422 =>
From 06471940e0cb917bb362cbcb9d872ab1336a04cf Mon Sep 17 00:00:00 2001
From: kPherox
Date: Tue, 7 Apr 2020 08:44:53 +0000
Subject: [PATCH 61/85] Apply suggestion to
test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
---
.../controllers/account_controller/update_credentials_test.exs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
index 8687d7995..d78fbc5a1 100644
--- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
+++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
@@ -298,7 +298,7 @@ test "update fields", %{conn: conn} do
]
end
- test "update fields by urlencoded", %{conn: conn} do
+ test "update fields via x-www-form-urlencoded", %{conn: conn} do
fields =
[
"fields_attributes[1][name]=link",
From 5739c498c029914c446656244cdd213a3e358fec Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Wed, 8 Apr 2020 18:46:01 +0300
Subject: [PATCH 62/85] fix for gun connections pool
---
CHANGELOG.md | 3 +++
lib/pleroma/gun/conn.ex | 4 +++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b6e5d807c..92d1abc4e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
+### Fixed
+- Gun connections pool `max_connections` option.
+
## [2.0.0] - 2019-03-08
### Security
- Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request.
diff --git a/lib/pleroma/gun/conn.ex b/lib/pleroma/gun/conn.ex
index 20823a765..cd25a2e74 100644
--- a/lib/pleroma/gun/conn.ex
+++ b/lib/pleroma/gun/conn.ex
@@ -49,8 +49,10 @@ def open(%URI{} = uri, name, opts) do
key = "#{uri.scheme}:#{uri.host}:#{uri.port}"
+ max_connections = pool_opts[:max_connections] || 250
+
conn_pid =
- if Connections.count(name) < opts[:max_connection] do
+ if Connections.count(name) < max_connections do
do_open(uri, opts)
else
close_least_used_and_do_open(name, uri, opts)
From d067eaa7b3bb76e7fc5ae019d6e00510b657171d Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Wed, 8 Apr 2020 22:58:31 +0300
Subject: [PATCH 63/85] formatter.ex: Use Phoenix.HTML for mention/hashtag
generation
Unlike concatenating strings, this makes sure everything is escaped.
Tests had to be changed because Phoenix.HTML runs attributes through
Enum.sort before generation for whatever reason.
---
lib/pleroma/formatter.ex | 26 ++++++++++++++++---
test/formatter_test.exs | 24 +++++++----------
test/user_test.exs | 2 +-
test/web/common_api/common_api_utils_test.exs | 6 ++---
.../update_credentials_test.exs | 4 +--
.../notification_controller_test.exs | 4 +--
test/web/twitter_api/twitter_api_test.exs | 2 +-
7 files changed, 41 insertions(+), 27 deletions(-)
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index e2a658cb3..c44e7fc8b 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -35,9 +35,19 @@ def mention_handler("@" <> nickname, buffer, opts, acc) do
nickname_text = get_nickname_text(nickname, opts)
link =
- ~s(@#{
- nickname_text
- })
+ Phoenix.HTML.Tag.content_tag(
+ :span,
+ Phoenix.HTML.Tag.content_tag(
+ :a,
+ ["@", Phoenix.HTML.Tag.content_tag(:span, nickname_text)],
+ "data-user": id,
+ class: "u-url mention",
+ href: ap_id,
+ rel: "ugc"
+ ),
+ class: "h-card"
+ )
+ |> Phoenix.HTML.safe_to_string()
{link, %{acc | mentions: MapSet.put(acc.mentions, {"@" <> nickname, user})}}
@@ -49,7 +59,15 @@ 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 = ~s(#{tag_text})
+
+ link =
+ Phoenix.HTML.Tag.content_tag(:a, tag_text,
+ class: "hashtag",
+ "data-tag": tag,
+ href: url,
+ rel: "tag ugc"
+ )
+ |> Phoenix.HTML.safe_to_string()
{link, %{acc | tags: MapSet.put(acc.tags, {tag_text, tag})}}
end
diff --git a/test/formatter_test.exs b/test/formatter_test.exs
index cf8441cf6..93fd8eab7 100644
--- a/test/formatter_test.exs
+++ b/test/formatter_test.exs
@@ -150,13 +150,13 @@ test "gives a replacement for user links, using local nicknames in user links te
assert length(mentions) == 3
expected_text =
- ~s(@gsimg According to @gsimg According to @archa_eme_, that is @daggsy. Also hello @archa_eme_, that is @daggsy. Also hello @archaeme)
+ }" href="#{archaeme_remote.ap_id}" rel="ugc">@archaeme)
assert expected_text == text
end
@@ -171,7 +171,7 @@ test "gives a replacement for user links when the user is using Osada" do
assert length(mentions) == 1
expected_text =
- ~s(@mike test)
@@ -187,7 +187,7 @@ test "gives a replacement for single-character local nicknames" do
assert length(mentions) == 1
expected_text =
- ~s(@o hi)
+ ~s(@o hi)
assert expected_text == text
end
@@ -209,17 +209,13 @@ 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 ==
- ~s(@#{user.nickname} @#{user.nickname} @#{
- other_user.nickname
- } hey dudes i hate @#{other_user.nickname} hey dudes i hate @#{
- third_user.nickname
- })
+ }" 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 0479f294d..d39787f35 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -1404,7 +1404,7 @@ test "preserves hosts in user links text" do
bio = "A.k.a. @nick@domain.com"
expected_text =
- ~s(A.k.a. @nick@domain.com)
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index d383d1714..98cf02d49 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -159,11 +159,11 @@ test "works for text/markdown with mentions" do
{output, _, _} = Utils.format_input(text, "text/markdown")
assert output ==
- ~s(hello world
another @user__test and @user__test and @user__test google.com paragraph
)
+ }" href="http://foo.com/user__test" rel="ugc">@user__test google.com paragraph
)
end
end
diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
index d78fbc5a1..2d256f63c 100644
--- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
+++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
@@ -82,9 +82,9 @@ test "updates the user's bio", %{conn: conn} do
assert user_data = json_response(conn, 200)
assert user_data["note"] ==
- ~s(I drink #cofe with #cofe with @#{user2.nickname}
suya..)
+ }" href="#{user2.ap_id}" rel="ugc">@#{user2.nickname}
suya..)
end
test "updates the user's locking status", %{conn: conn} do
diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs
index 344eabb4a..6f1fab069 100644
--- a/test/web/mastodon_api/controllers/notification_controller_test.exs
+++ b/test/web/mastodon_api/controllers/notification_controller_test.exs
@@ -26,7 +26,7 @@ test "list of notifications" do
|> get("/api/v1/notifications")
expected_response =
- "hi @#{user.nickname}"
@@ -45,7 +45,7 @@ test "getting a single notification" do
conn = get(conn, "/api/v1/notifications/#{notification.id}")
expected_response =
- "hi @#{user.nickname}"
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index 92f9aa0f5..f6e13b661 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -109,7 +109,7 @@ test "it registers a new user and parses mentions in the bio" do
{:ok, user2} = TwitterAPI.register_user(data2)
expected_text =
- ~s(@john test)
From c401b00c7885823744183dbd077db9239585d20d Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Thu, 9 Apr 2020 04:36:39 +0200
Subject: [PATCH 64/85] ObjectValidators.Types.ObjectID: Fix when URI.parse
returns %URL{host: ""}
---
.../object_validators/types/object_id.ex | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
index ee10be0b0..f6e749b33 100644
--- a/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
@@ -6,14 +6,10 @@ def type, do: :string
def cast(object) when is_binary(object) do
# Host has to be present and scheme has to be an http scheme (for now)
case URI.parse(object) do
- %URI{host: nil} ->
- :error
-
- %URI{scheme: scheme} when scheme in ["https", "http"] ->
- {:ok, object}
-
- _ ->
- :error
+ %URI{host: nil} -> :error
+ %URI{host: ""} -> :error
+ %URI{scheme: scheme} when scheme in ["https", "http"] -> {:ok, object}
+ _ -> :error
end
end
From 73134e248a031613151df87fdd406580d16dc6b9 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Thu, 9 Apr 2020 08:03:21 +0300
Subject: [PATCH 65/85] no changelog entry - bug fixed only in develop
---
CHANGELOG.md | 3 ---
1 file changed, 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92d1abc4e..b6e5d807c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,9 +20,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
-### Fixed
-- Gun connections pool `max_connections` option.
-
## [2.0.0] - 2019-03-08
### Security
- Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request.
From c8bfbf511eeca2045267ad4792c35648625788cf Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Thu, 9 Apr 2020 10:17:24 +0000
Subject: [PATCH 66/85] Apply suggestion to docs/API/admin_api.md
---
docs/API/admin_api.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md
index 179d8c451..b3cf89818 100644
--- a/docs/API/admin_api.md
+++ b/docs/API/admin_api.md
@@ -400,7 +400,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
```json
[
{
- `error` // error message
+ "error": "Appropriate error message here"
}
]
```
From 4c60fdcbb1ab06183b8e300cbbb84d70ecd3e25b Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Thu, 9 Apr 2020 10:17:31 +0000
Subject: [PATCH 67/85] Apply suggestion to
lib/pleroma/web/admin_api/admin_api_controller.ex
---
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 7b442f6e1..a66db68f3 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -592,7 +592,7 @@ def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params)
{:registrations_open, _} ->
errors(
conn,
- {:error, "To send invites you need set `registrations_open` option to false."}
+ {:error, "To send invites you need to set the `registrations_open` option to false."}
)
{:invites_enabled, _} ->
From 1cf0d5ab0d579ee4a1a779c308fedb0ab8ec3884 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Thu, 9 Apr 2020 10:17:36 +0000
Subject: [PATCH 68/85] Apply suggestion to
lib/pleroma/web/admin_api/admin_api_controller.ex
---
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 a66db68f3..09959b3bf 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -598,7 +598,7 @@ def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params)
{:invites_enabled, _} ->
errors(
conn,
- {:error, "To send invites you need set `invites_enabled` option to true."}
+ {:error, "To send invites you need set to set the `invites_enabled` option to true."}
)
end
end
From 365c34a7a96a9cbd5acb30eb6eedf195eeaff131 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Thu, 9 Apr 2020 10:17:44 +0000
Subject: [PATCH 69/85] Apply suggestion to
test/web/admin_api/admin_api_controller_test.exs
---
test/web/admin_api/admin_api_controller_test.exs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 32fe69d19..afd894269 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -671,7 +671,7 @@ test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
assert json_response(conn, :bad_request) ==
- "To send invites you need set `invites_enabled` option to true."
+ "To send invites you need to set the `invites_enabled` option to true."
end
test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
From 9795ff5b016e74c0e7b94ac2ea28023208d1f8ee Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Thu, 9 Apr 2020 10:17:50 +0000
Subject: [PATCH 70/85] Apply suggestion to
test/web/admin_api/admin_api_controller_test.exs
---
test/web/admin_api/admin_api_controller_test.exs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index afd894269..e8d11b88c 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -681,7 +681,7 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
assert json_response(conn, :bad_request) ==
- "To send invites you need set `registrations_open` option to false."
+ "To send invites you need to set the `registrations_open` option to false."
end
end
From f20a19de853e8834f7774ee0098a14213bc7427f Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov
Date: Thu, 9 Apr 2020 13:28:54 +0300
Subject: [PATCH 71/85] typo fix
---
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 09959b3bf..fdbd24acb 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -598,7 +598,7 @@ def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params)
{:invites_enabled, _} ->
errors(
conn,
- {:error, "To send invites you need set to set the `invites_enabled` option to true."}
+ {:error, "To send invites you need to set the `invites_enabled` option to true."}
)
end
end
From d37a102933dbfbb0996546b4d148bbe36fbd4220 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Thu, 9 Apr 2020 21:16:29 +0900
Subject: [PATCH 72/85] Fix OTP_VERSION file in docker
---
Dockerfile | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Dockerfile b/Dockerfile
index 29931a5e3..c2f3ad98c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,6 +12,8 @@ RUN apk add git gcc g++ musl-dev make &&\
mkdir release &&\
mix release --path release
+RUN echo "${OTP_VERSION}" > release/OTP_VERSION
+
FROM alpine:3.11
ARG BUILD_DATE
From d545b883eb3c5b79b89a49ccaf9256c31b401145 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Thu, 9 Apr 2020 17:08:43 +0400
Subject: [PATCH 73/85] Add `/api/v1/notifications/:id/dismiss` endpoint
---
.../controllers/notification_controller.ex | 3 ++-
lib/pleroma/web/router.ex | 4 +++-
.../notification_controller_test.exs | 18 +++++++++++++++++-
3 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
index 0c9218454..a6b4096ec 100644
--- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
@@ -66,7 +66,8 @@ def clear(%{assigns: %{user: user}} = conn, _params) do
json(conn, %{})
end
- # POST /api/v1/notifications/dismiss
+ # POST /api/v1/notifications/:id/dismiss
+ # POST /api/v1/notifications/dismiss (deprecated)
def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
with {:ok, _notif} <- Notification.dismiss(user, id) do
json(conn, %{})
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 3ecd59cd1..5f5ec1c81 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -352,9 +352,11 @@ defmodule Pleroma.Web.Router do
get("/notifications", NotificationController, :index)
get("/notifications/:id", NotificationController, :show)
+ post("/notifications/:id/dismiss", NotificationController, :dismiss)
post("/notifications/clear", NotificationController, :clear)
- post("/notifications/dismiss", NotificationController, :dismiss)
delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple)
+ # Deprecated: was removed in Mastodon v3, use `/notifications/:id/dismiss` instead
+ post("/notifications/dismiss", NotificationController, :dismiss)
get("/scheduled_statuses", ScheduledActivityController, :index)
get("/scheduled_statuses/:id", ScheduledActivityController, :show)
diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs
index 6f1fab069..1557937d8 100644
--- a/test/web/mastodon_api/controllers/notification_controller_test.exs
+++ b/test/web/mastodon_api/controllers/notification_controller_test.exs
@@ -53,7 +53,7 @@ test "getting a single notification" do
assert response == expected_response
end
- test "dismissing a single notification" do
+ test "dismissing a single notification (deprecated endpoint)" do
%{user: user, conn: conn} = oauth_access(["write:notifications"])
other_user = insert(:user)
@@ -69,6 +69,22 @@ test "dismissing a single notification" do
assert %{} = json_response(conn, 200)
end
+ test "dismissing a single notification" do
+ %{user: user, conn: conn} = oauth_access(["write:notifications"])
+ 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/#{notification.id}/dismiss")
+
+ assert %{} = json_response(conn, 200)
+ end
+
test "clearing all notifications" do
%{user: user, conn: conn} = oauth_access(["write:notifications", "read:notifications"])
other_user = insert(:user)
From 0e8f6d24b87812664d3bb021d17f120686cf2401 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Fri, 10 Apr 2020 00:19:09 +0900
Subject: [PATCH 74/85] Create OTP_VERSION file by `mix release`
---
Dockerfile | 2 --
mix.exs | 11 ++++++++++-
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index c2f3ad98c..29931a5e3 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,8 +12,6 @@ RUN apk add git gcc g++ musl-dev make &&\
mkdir release &&\
mix release --path release
-RUN echo "${OTP_VERSION}" > release/OTP_VERSION
-
FROM alpine:3.11
ARG BUILD_DATE
diff --git a/mix.exs b/mix.exs
index 3e4c7cbd8..ad2029518 100644
--- a/mix.exs
+++ b/mix.exs
@@ -37,12 +37,21 @@ def project do
pleroma: [
include_executables_for: [:unix],
applications: [ex_syslogger: :load, syslog: :load],
- steps: [:assemble, ©_files/1, ©_nginx_config/1]
+ steps: [:assemble, &put_files/1, ©_files/1, ©_nginx_config/1]
]
]
]
end
+ def put_files(%{path: target_path} = release) do
+ File.write!(
+ Path.join([target_path, "OTP_VERSION"]),
+ Pleroma.OTPVersion.version()
+ )
+
+ release
+ end
+
def copy_files(%{path: target_path} = release) do
File.cp_r!("./rel/files", target_path)
release
From c826d5195f1746449eb369e86a730f14de9fa267 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Thu, 9 Apr 2020 23:36:17 +0400
Subject: [PATCH 75/85] Update CHANGELOG
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b6e5d807c..2f5d8f612 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
API Changes
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
+- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
## [2.0.0] - 2019-03-08
From 781ac28859596fce5f2fd24ffe1cdf24caaaa2fc Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Sun, 15 Mar 2020 17:26:58 +0300
Subject: [PATCH 76/85] changelog.md: add 2.0.1 entry
---
CHANGELOG.md | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2f5d8f612..15f0463b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,9 +3,19 @@ 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]
+## [2.0.1] - 2020-03-15
+### Fixed
+- 500 errors when no `Accept` header is present if Static-FE is enabled
+- Instance panel not being updated immediately due to wrong `Cache-Control` headers
+- Statuses posted with BBCode/Markdown having unncessary newlines in Pleroma-FE
+- OTP: Fix some settings not being migrated to in-database config properly
+- No `Cache-Control` headers on attachment/media proxy requests
+- Character limit enforcement being off by 1
+- Mastodon Streaming API: hashtag timelines not working
+
### Changed
-- **Breaking:** BBCode and Markdown formatters will no longer return any `\n` and only use `
` for newlines
+- BBCode and Markdown formatters will no longer return any `\n` and only use `
` for newlines
+- Mastodon API: Allow registration without email if email verification is not enabled
### Removed
- **Breaking:** removed `with_move` parameter from notifications timeline.
From 2a08f44b026bae611064b6ac459e7df16e4a36f9 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Mon, 16 Mar 2020 00:50:03 +0300
Subject: [PATCH 77/85] CHANGELOG.md: Add upgrade notes for 2.0.1
---
CHANGELOG.md | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15f0463b2..8c976228c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,21 @@ 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]
+### Removed
+- **Breaking:** removed `with_move` parameter from notifications timeline.
+
+### Added
+- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
+- NodeInfo: `pleroma_emoji_reactions` to the `features` list.
+- Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
+- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma won’t start. For hackney OTP update is not required.
+
+ API Changes
+- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
+- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
+
+
## [2.0.1] - 2020-03-15
### Fixed
- 500 errors when no `Accept` header is present if Static-FE is enabled
@@ -17,19 +32,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- BBCode and Markdown formatters will no longer return any `\n` and only use `
` for newlines
- Mastodon API: Allow registration without email if email verification is not enabled
-### Removed
-- **Breaking:** removed `with_move` parameter from notifications timeline.
+### Upgrade notes
+#### Nginx only
+1. Remove `proxy_ignore_headers Cache-Control;` and `proxy_hide_header Cache-Control;` from your config.
-### Added
-- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
-- NodeInfo: `pleroma_emoji_reactions` to the `features` list.
-- Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
-- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma won’t start. For hackney OTP update is not required.
-
- API Changes
-- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
-- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
-
+#### Everyone
+1. Run database migrations (inside Pleroma directory):
+ - OTP: `./bin/pleroma_ctl migrate`
+ - From Source: `mix ecto.migrate`
+2. Restart Pleroma
## [2.0.0] - 2019-03-08
### Security
From 7306d2d06942f7912fd42809b1feb9ac43089012 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 31 Mar 2020 13:59:26 +0300
Subject: [PATCH 78/85] CHANGELOG.md: Add 2.0.2 entry
---
CHANGELOG.md | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c976228c..6942ad0bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
+## [2.0.2] - 2020-03-31
+### Fixed
+- Blocked/muted users still generating push notifications
+- Input textbox for bio ignoring newlines
+- OTP: Inability to use PostgreSQL databases with SSL
+- `user delete_activities` breaking when trying to delete already deleted posts
+
+### Added
+- Admin API: `PATCH /api/pleroma/admin/users/:nickname/update_credentials`
+
## [2.0.1] - 2020-03-15
+### Security
+- Static-FE: Fix remote posts not being sanitized
+
### Fixed
- 500 errors when no `Accept` header is present if Static-FE is enabled
- Instance panel not being updated immediately due to wrong `Cache-Control` headers
From 0b8f9a66aefdf4c9e2b7c1fa931e19cd724b6b4b Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Thu, 2 Apr 2020 23:37:14 +0300
Subject: [PATCH 79/85] CHANGELOG.md: add entries for funkwhale-related changes
---
CHANGELOG.md | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6942ad0bf..8eed9cf7d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,14 +19,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [2.0.2] - 2020-03-31
+### Added
+- Support for Funkwhale's `Audio` activity
+- Admin API: `PATCH /api/pleroma/admin/users/:nickname/update_credentials`
+
### Fixed
- Blocked/muted users still generating push notifications
- Input textbox for bio ignoring newlines
- OTP: Inability to use PostgreSQL databases with SSL
- `user delete_activities` breaking when trying to delete already deleted posts
-
-### Added
-- Admin API: `PATCH /api/pleroma/admin/users/:nickname/update_credentials`
+- Incorrect URL for Funkwhale channels
## [2.0.1] - 2020-03-15
### Security
From adeb82e4966a505e9ac65743e6336db27558e38f Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Wed, 8 Apr 2020 00:38:48 +0300
Subject: [PATCH 80/85] CHANGELOG.md: add 2.0.2 update notes
---
CHANGELOG.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8eed9cf7d..408b932b8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,6 +30,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `user delete_activities` breaking when trying to delete already deleted posts
- Incorrect URL for Funkwhale channels
+### Upgrade notes
+1. Restart Pleroma
+
## [2.0.1] - 2020-03-15
### Security
- Static-FE: Fix remote posts not being sanitized
From 9abf13abe05f3f53bdf21d4d97242e571b1767c6 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Wed, 8 Apr 2020 00:39:55 +0300
Subject: [PATCH 81/85] CHANGELOG.md: update 2.0.2 release date
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 408b932b8..bac69ad6a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
-## [2.0.2] - 2020-03-31
+## [2.0.2] - 2020-04-08
### Added
- Support for Funkwhale's `Audio` activity
- Admin API: `PATCH /api/pleroma/admin/users/:nickname/update_credentials`
From c2aad36aa86694d4131adb2ed47441beca2ab2e8 Mon Sep 17 00:00:00 2001
From: kPherox
Date: Thu, 9 Apr 2020 23:19:41 +0000
Subject: [PATCH 82/85] Rename function
---
mix.exs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mix.exs b/mix.exs
index ad2029518..a1fcde564 100644
--- a/mix.exs
+++ b/mix.exs
@@ -37,13 +37,13 @@ def project do
pleroma: [
include_executables_for: [:unix],
applications: [ex_syslogger: :load, syslog: :load],
- steps: [:assemble, &put_files/1, ©_files/1, ©_nginx_config/1]
+ steps: [:assemble, &put_otp_version/1, ©_files/1, ©_nginx_config/1]
]
]
]
end
- def put_files(%{path: target_path} = release) do
+ def put_otp_version(%{path: target_path} = release) do
File.write!(
Path.join([target_path, "OTP_VERSION"]),
Pleroma.OTPVersion.version()
From 6ff8812ea3403a2f4a31206a96a58fad93fff51f Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Fri, 10 Apr 2020 11:37:02 -0500
Subject: [PATCH 83/85] Add a section for changelog entries that pertain to the
next patch release.
This will make it easier to keep changelogs synced between develop and stable branches.
---
CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd5d5f800..36897503a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed
- Support pagination in conversations API
+## [unreleased-patch]
+
## [2.0.2] - 2020-04-08
### Added
- Support for Funkwhale's `Audio` activity
From ad92cef844d4f4211a65fd37b08f8bd8abea8dda Mon Sep 17 00:00:00 2001
From: Maksim Pechnikov
Date: Fri, 10 Apr 2020 21:27:50 +0300
Subject: [PATCH 84/85] fix Oban migration
---
.../repo/migrations/20200402063221_update_oban_jobs_table.exs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs b/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs
index c8ee12192..e7ff04008 100644
--- a/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs
+++ b/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs
@@ -2,10 +2,10 @@ defmodule Pleroma.Repo.Migrations.UpdateObanJobsTable do
use Ecto.Migration
def up do
- Oban.Migrations.up()
+ Oban.Migrations.up(version: 8)
end
def down do
- Oban.Migrations.down(version: 1)
+ Oban.Migrations.down(version: 7)
end
end
From 2ba754ffe11b98305e0c0607fec7ca4d510aa67f Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Sun, 12 Apr 2020 18:49:31 +0300
Subject: [PATCH 85/85] Fix mix tasks failing on OTP releases
No idea why this was even added.
Closes #1678
---
lib/mix/pleroma.ex | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex
index 4dfcc32e7..3ad6edbfb 100644
--- a/lib/mix/pleroma.ex
+++ b/lib/mix/pleroma.ex
@@ -5,7 +5,6 @@
defmodule Mix.Pleroma do
@doc "Common functions to be reused in mix tasks"
def start_pleroma do
- Mix.Task.run("app.start")
Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
if Pleroma.Config.get(:env) != :test do