Add user upgrade function.
authorlain <lain@soykaf.club>
Wed, 21 Feb 2018 21:21:40 +0000 (22:21 +0100)
committerlain <lain@soykaf.club>
Wed, 21 Feb 2018 21:21:40 +0000 (22:21 +0100)
lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
test/web/activity_pub/transmogrifier_test.exs

index a902c57e39553091faf1f03084e769eb8ef17f1f..1d9f40ee0852970be0d6cbd6a1ecfea4d44bac67 100644 (file)
@@ -103,6 +103,15 @@ defmodule Pleroma.User do
     |> validate_length(:name, min: 1, max: 100)
   end
 
+  def upgrade_changeset(struct, params \\ %{}) do
+    struct
+    |> cast(params, [:bio, :name, :info, :follower_address])
+    |> unique_constraint(:nickname)
+    |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/)
+    |> validate_length(:bio, min: 1, max: 1000)
+    |> validate_length(:name, min: 1, max: 100)
+  end
+
   def password_update_changeset(struct, params) do
     changeset = struct
     |> cast(params, [:password, :password_confirmation])
index 554d3a00800b151349743b617cc9eaf7e34c2170..0de730410c642dd1669f9de56b14f6adf454bd44 100644 (file)
@@ -260,7 +260,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     Repo.insert(%Object{data: data})
   end
 
-  def make_user_from_ap_id(ap_id) do
+  def fetch_and_prepare_user_from_ap_id(ap_id) do
     with {:ok, %{status_code: 200, body: body}} <- @httpoison.get(ap_id, ["Accept": "application/activity+json"]),
     {:ok, data} <- Poison.decode(body)
       do
@@ -271,14 +271,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
           "source_data" => data
         },
         nickname: "#{data["preferredUsername"]}@#{URI.parse(ap_id).host}",
-        name: data["name"]
+        name: data["name"],
+        follower_address: data["followers"]
       }
 
-      if user = User.get_by_ap_id(ap_id) do
-        User.info_changeset(user, user_data)
-        |> Repo.update
+      {:ok, user_data}
+    end
+  end
+
+  def make_user_from_ap_id(ap_id) do
+    if user = User.get_by_ap_id(ap_id) do
+      Transmogrifier.upgrade_user_from_ap_id(ap_id)
+    else
+      with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
+        User.insert_or_update_user(data)
       else
-        User.insert_or_update_user(user_data)
+        e -> e
       end
     end
   end
index eb2569ef200cd6b412dc33d1ea869891c914a1d0..395436c5c9ee81b90ea0dd5f77366d3c691dc87b 100644 (file)
@@ -5,8 +5,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   alias Pleroma.User
   alias Pleroma.Object
   alias Pleroma.Activity
+  alias Pleroma.Repo
   alias Pleroma.Web.ActivityPub.ActivityPub
 
+  import Ecto.Query
+
   @doc """
   Modifies an incoming AP object (mastodon format) to our internal format.
   """
@@ -180,4 +183,33 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     object
     |> Map.put("attachment", attachments)
   end
+
+  def upgrade_user_from_ap_id(ap_id) do
+    with %User{} = user <- User.get_by_ap_id(ap_id),
+         {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id) do
+      data = data
+      |> Map.put(:info, Map.merge(user.info, data[:info]))
+
+      old_follower_address = user.follower_address
+      {:ok, user} = User.upgrade_changeset(user, data)
+      |> Repo.update()
+
+      # This could potentially take a long time, do it in the background
+      Task.start(fn ->
+        q  = from a in Activity,
+        where: ^old_follower_address in a.recipients,
+        update: [set: [recipients: fragment("array_replace(?,?,?)", a.recipients, ^old_follower_address, ^user.follower_address)]]
+        Repo.update_all(q, [])
+
+        q  = from u in User,
+        where: ^old_follower_address in u.following,
+        update: [set: [following: fragment("array_replace(?,?,?)", u.following, ^old_follower_address, ^user.follower_address)]]
+        Repo.update_all(q, [])
+      end)
+
+      {:ok, user}
+    else
+      e -> e
+    end
+  end
 end
index 96dd630575ab21779e7e4def81cd87d57e26fd25..1857348527da6c97c8ee2b0dae2f1cb0047837a3 100644 (file)
@@ -178,4 +178,40 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert modified["object"]["actor"] == modified["object"]["attributedTo"]
     end
   end
+
+  describe "user upgrade" do
+    test "it upgrades a user to activitypub" do
+      user = insert(:user, %{local: false, ap_id: "https://niu.moe/users/rye", follower_address: "..."})
+      user_two = insert(:user, %{following: [user.follower_address]})
+
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
+      {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
+      assert "..." in activity.recipients
+
+      user = Repo.get(User, user.id)
+      assert user.info["note_count"] == 1
+
+      {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
+      assert user.info["ap_enabled"]
+      assert user.info["note_count"] == 1
+      assert user.follower_address == "https://niu.moe/users/rye/followers"
+
+      # Wait for the background task
+      :timer.sleep(1000)
+
+      user = Repo.get(User, user.id)
+      assert user.info["note_count"] == 1
+
+      activity = Repo.get(Activity, activity.id)
+      assert user.follower_address in activity.recipients
+      refute "..." in activity.recipients
+
+      unrelated_activity = Repo.get(Activity, unrelated_activity.id)
+      refute user.follower_address in unrelated_activity.recipients
+
+      user_two = Repo.get(User, user_two.id)
+      assert user.follower_address in user_two.following
+      refute "..." in user_two.following
+    end
+  end
 end