Document follow relationship updates and cleanup
authorEgor Kislitsyn <egor@kislitsyn.com>
Wed, 2 Dec 2020 15:16:36 +0000 (19:16 +0400)
committerEgor Kislitsyn <egor@kislitsyn.com>
Wed, 2 Dec 2020 15:16:36 +0000 (19:16 +0400)
docs/API/differences_in_mastoapi_responses.md
lib/pleroma/following_relationship.ex
lib/pleroma/web/streamer.ex
lib/pleroma/web/views/streamer_view.ex
test/pleroma/web/streamer_test.exs

index 6b0ad85d13bf13166885ddd01dd2c7b6ad0a0aa6..e6cc3aef14a82917a3d48b4767c0f1482833a0ab 100644 (file)
@@ -4,7 +4,7 @@ A Pleroma instance can be identified by "<Mastodon version> (compatible; Pleroma
 
 ## Flake IDs
 
-Pleroma uses 128-bit ids as opposed to Mastodon's 64 bits. However just like Mastodon's ids they are lexically sortable strings
+Pleroma uses 128-bit ids as opposed to Mastodon's 64 bits. However, just like Mastodon's ids, they are lexically sortable strings
 
 ## Timelines
 
@@ -26,8 +26,8 @@ Has these additional fields under the `pleroma` object:
 - `conversation_id`: the ID of the AP context the status is associated with (if any)
 - `direct_conversation_id`: the ID of the Mastodon direct message conversation the status is associated with (if any)
 - `in_reply_to_account_acct`: the `acct` property of User entity for replied user (if any)
-- `content`: a map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`
-- `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`
+- `content`: a map consisting of alternate representations of the `content` property with the key being its mimetype. Currently, the only alternate representation supported is `text/plain`
+- `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being its mimetype. Currently, the only alternate representation supported is `text/plain`
 - `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire
 - `thread_muted`: true if the thread the post belongs to is muted
 - `emoji_reactions`: A list with emoji / reaction maps. The format is `{name: "☕", count: 1, me: true}`. Contains no information about the reacting users, for that use the `/statuses/:id/reactions` endpoint.
@@ -170,9 +170,9 @@ Returns on success: 200 OK `{}`
 
 Additional parameters can be added to the JSON body/Form data:
 
-- `preview`: boolean, if set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
+- `preview`: boolean, if set to `true` the post won't be actually posted, but the status entity would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
 - `content_type`: string, contain the MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint.
-- `to`: A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply.
+- `to`: A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for post visibility are not affected by this and will still apply.
 - `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted`, `local` or `public`) it can be used to address a List by setting it to `list:LIST_ID`.
 - `expires_in`: The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour.
 - `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`.
@@ -279,10 +279,27 @@ Has these additional fields under the `pleroma` object:
 
 ## Streaming
 
+### Chats
+
 There is an additional `user:pleroma_chat` stream. Incoming chat messages will make the current chat be sent to this `user` stream. The `event` of an incoming chat message is `pleroma:chat_update`. The payload is the updated chat with the incoming chat message in the `last_message` field.
 
+### Remote timelines
+
 For viewing remote server timelines, there are `public:remote` and `public:remote:media` streams. Each of these accept a parameter like `?instance=lain.com`.
 
+### Follow relationships updates
+
+Pleroma streams follow relationships updatates as `pleroma:follow_relationships_update` events to the `user` stream.
+
+The message playload consist of:
+
+- `state`: a relationship state, one of `follow_pending`, `follow_accept` or `follow_reject`.
+
+- `follower` and `following` maps with following fields:
+  - `id`: user ID
+  - `follower_count`: follower count
+  - `following_count`: following count
+
 ## User muting and thread muting
 
 Both user muting and thread muting can be done for only a certain time by adding an `expires_in` parameter to the API calls and giving the expiration time in seconds.
index bc6a7eaf9850abdc10490e888e0a3f64becdd369..5390a58e1357e9475bb473b3c2c83077022ee824 100644 (file)
@@ -96,7 +96,7 @@ defmodule Pleroma.FollowingRelationship do
   defp after_update(state, %User{} = follower, %User{} = following) do
     with {:ok, following} <- User.update_follower_count(following),
          {:ok, follower} <- User.update_following_count(follower) do
-      Pleroma.Web.Streamer.stream("relationships:update", %{
+      Pleroma.Web.Streamer.stream("follow_relationship", %{
         state: state,
         following: following,
         follower: follower
index 0b6cc89e906b4f2d8858fb68261b0d288062e686..7d4a1304a9b381e3f25bfec72acd38398adcc070 100644 (file)
@@ -186,18 +186,15 @@ defmodule Pleroma.Web.Streamer do
     end)
   end
 
-  defp do_stream("relationships:update", item) do
-    text = StreamerView.render("relationships_update.json", item)
-
-    [item.follower, item.following]
-    |> Enum.map(fn %{id: id} -> "user:#{id}" end)
-    |> Enum.each(fn user_topic ->
-      Logger.debug("Trying to push relationships:update to #{user_topic}\n\n")
-
-      Registry.dispatch(@registry, user_topic, fn list ->
-        Enum.each(list, fn {pid, _auth} ->
-          send(pid, {:text, text})
-        end)
+  defp do_stream("follow_relationship", item) do
+    text = StreamerView.render("follow_relationships_update.json", item)
+    user_topic = "user:#{item.follower.id}"
+
+    Logger.debug("Trying to push follow relationship update to #{user_topic}\n\n")
+
+    Registry.dispatch(@registry, user_topic, fn list ->
+      Enum.each(list, fn {pid, _auth} ->
+        send(pid, {:text, text})
       end)
     end)
   end
index 92239a411c254771e144a6c6137d487a68d33361..4fc14166dd4a44c76be3be6ffec890e089f16a27 100644 (file)
@@ -74,9 +74,9 @@ defmodule Pleroma.Web.StreamerView do
     |> Jason.encode!()
   end
 
-  def render("relationships_update.json", item) do
+  def render("follow_relationships_update.json", item) do
     %{
-      event: "pleroma:relationships_update",
+      event: "pleroma:follow_relationships_update",
       payload:
         %{
           state: item.state,
index 3229ba6f9c90d0990a037d72d32de01668960f6d..ad66ddc9d6dc75876bbc5905fae36f6d023a6d64 100644 (file)
@@ -404,15 +404,14 @@ defmodule Pleroma.Web.StreamerTest do
       refute Streamer.filtered_by_user?(user, notif)
     end
 
-    test "it sends relationships updates to the 'user' stream", %{
+    test "it sends follow relationships updates to the 'user' stream", %{
       user: user,
       token: oauth_token
     } do
       user_id = user.id
       user_url = user.ap_id
-      follower = insert(:user)
-      follower_token = insert(:oauth_token, user: follower)
-      follower_id = follower.id
+      other_user = insert(:user)
+      other_user_id = other_user.id
 
       body =
         File.read!("test/fixtures/users_mock/localhost.json")
@@ -425,47 +424,42 @@ defmodule Pleroma.Web.StreamerTest do
       end)
 
       Streamer.get_topic_and_add_socket("user", user, oauth_token)
-      Streamer.get_topic_and_add_socket("user", follower, follower_token)
-      {:ok, _follower, _followed, _follow_activity} = CommonAPI.follow(follower, user)
+      {:ok, _follower, _followed, _follow_activity} = CommonAPI.follow(user, other_user)
 
-      # follow_pending event sent to both follower and following
       assert_receive {:text, event}
-      assert_receive {:text, ^event}
 
-      assert %{"event" => "pleroma:relationships_update", "payload" => payload} =
+      assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} =
                Jason.decode!(event)
 
       assert %{
                "follower" => %{
                  "follower_count" => 0,
                  "following_count" => 0,
-                 "id" => ^follower_id
+                 "id" => ^user_id
                },
                "following" => %{
                  "follower_count" => 0,
                  "following_count" => 0,
-                 "id" => ^user_id
+                 "id" => ^other_user_id
                },
                "state" => "follow_pending"
              } = Jason.decode!(payload)
 
-      # follow_accept event sent to both follower and following
       assert_receive {:text, event}
-      assert_receive {:text, ^event}
 
-      assert %{"event" => "pleroma:relationships_update", "payload" => payload} =
+      assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} =
                Jason.decode!(event)
 
       assert %{
                "follower" => %{
                  "follower_count" => 0,
                  "following_count" => 1,
-                 "id" => ^follower_id
+                 "id" => ^user_id
                },
                "following" => %{
                  "follower_count" => 1,
                  "following_count" => 0,
-                 "id" => ^user_id
+                 "id" => ^other_user_id
                },
                "state" => "follow_accept"
              } = Jason.decode!(payload)