make bulk user creation from admin works as a transaction
authorSachin Joshi <satchin.joshi@gmail.com>
Sat, 1 Jun 2019 05:32:53 +0000 (11:17 +0545)
committerSachin Joshi <satchin.joshi@gmail.com>
Sat, 1 Jun 2019 05:32:53 +0000 (11:17 +0545)
lib/pleroma/user.ex
lib/pleroma/web/admin_api/admin_api_controller.ex
lib/pleroma/web/admin_api/views/account_view.ex
test/web/admin_api/admin_api_controller_test.exs

index c6a562a6143f22318df27cdf6fea6fbcbbc51f4e..722e8ff6b0736d94bf6b364bd47336f7dee3100c 100644 (file)
@@ -276,7 +276,13 @@ defmodule Pleroma.User do
   @doc "Inserts provided changeset, performs post-registration actions (confirmation email sending etc.)"
   def register(%Ecto.Changeset{} = changeset) do
     with {:ok, user} <- Repo.insert(changeset),
-         {:ok, user} <- autofollow_users(user),
+         {:ok, user} <- post_register_action(user) do
+      {:ok, user}
+    end
+  end
+
+  def post_register_action(%User{} = user) do
+    with {:ok, user} <- autofollow_users(user),
          {:ok, user} <- set_cache(user),
          {:ok, _} <- Pleroma.User.WelcomeMessage.post_welcome_message_to_user(user),
          {:ok, _} <- try_send_confirmation_email(user) do
index 6048ed35b70cfbefbfae88319c375eea633b51c5..60fd4e57199dc531f8460ce58d9c259ac20a2729 100644 (file)
@@ -47,7 +47,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
   end
 
   def users_create(conn, %{"users" => users}) do
-    result =
+    changesets =
       Enum.map(users, fn %{"nickname" => nickname, "email" => email, "password" => password} ->
         user_data = %{
           nickname: nickname,
@@ -58,19 +58,40 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
           bio: "."
         }
 
-        changeset = User.register_changeset(%User{}, user_data, need_confirmation: false)
+        User.register_changeset(%User{}, user_data, need_confirmation: false)
+      end)
+      |> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
+        Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
+      end)
 
-        case User.register(changeset) do
-          {:ok, user} ->
-            AccountView.render("created.json", %{user: user})
+    case Pleroma.Repo.transaction(changesets) do
+      {:ok, users} ->
+        res =
+          users
+          |> Map.values()
+          |> Enum.map(fn user ->
+            {:ok, user} = User.post_register_action(user)
+            user
+          end)
+          |> Enum.map(&AccountView.render("created.json", %{user: &1}))
 
-          {:error, changeset} ->
-            AccountView.render("create-error.json", %{changeset: changeset})
-        end
-      end)
+        conn
+        |> json(res)
 
-    conn
-    |> json(result)
+      {:error, id, changeset, _} ->
+        res =
+          Enum.map(changesets.operations, fn
+            {current_id, {:changeset, _current_changeset, _}} when current_id == id ->
+              AccountView.render("create-error.json", %{changeset: changeset})
+
+            {_, {:changeset, current_changeset, _}} ->
+              AccountView.render("create-error.json", %{changeset: current_changeset})
+          end)
+
+        conn
+        |> put_status(:conflict)
+        |> json(res)
+    end
   end
 
   def user_show(conn, %{"nickname" => nickname}) do
index e1825c5f1401111aa58e24682dc1f1dbc57ac79e..cccdeff7e93f1abe4c66043fd5d487b4b612c348 100644 (file)
@@ -48,7 +48,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
   def render("created.json", %{user: user}) do
     %{
       type: "success",
-      code: 201,
+      code: 200,
       data: %{
         nickname: user.nickname,
         email: user.email
index a0c9fd56fcceb53b20a3ab1c8182380d261a84cb..0199051374cab85b0cb1a7c06f5d384b7b89a5b3 100644 (file)
@@ -36,18 +36,31 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
               "nickname" => "lain",
               "email" => "lain@example.org",
               "password" => "test"
+            },
+            %{
+              "nickname" => "lain2",
+              "email" => "lain2@example.org",
+              "password" => "test"
             }
           ]
         })
 
       assert json_response(conn, 200) == [
                %{
-                 "code" => 201,
+                 "code" => 200,
                  "data" => %{
                    "email" => "lain@example.org",
                    "nickname" => "lain"
                  },
                  "type" => "success"
+               },
+               %{
+                 "code" => 200,
+                 "data" => %{
+                   "email" => "lain2@example.org",
+                   "nickname" => "lain2"
+                 },
+                 "type" => "success"
                }
              ]
     end
@@ -70,7 +83,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
           ]
         })
 
-      assert json_response(conn, 200) == [
+      assert json_response(conn, 409) == [
                %{
                  "code" => 409,
                  "data" => %{
@@ -101,7 +114,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
           ]
         })
 
-      assert json_response(conn, 200) == [
+      assert json_response(conn, 409) == [
                %{
                  "code" => 409,
                  "data" => %{
@@ -113,6 +126,53 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                }
              ]
     end
+
+    test "Multiple user creation works in transaction" do
+      admin = insert(:user, info: %{is_admin: true})
+      user = insert(:user)
+
+      conn =
+        build_conn()
+        |> assign(:user, admin)
+        |> put_req_header("accept", "application/json")
+        |> post("/api/pleroma/admin/users", %{
+          "users" => [
+            %{
+              "nickname" => "newuser",
+              "email" => "newuser@pleroma.social",
+              "password" => "test"
+            },
+            %{
+              "nickname" => "lain",
+              "email" => user.email,
+              "password" => "test"
+            }
+          ]
+        })
+
+      assert json_response(conn, 409) == [
+               %{
+                 "code" => 409,
+                 "data" => %{
+                   "email" => user.email,
+                   "nickname" => "lain"
+                 },
+                 "error" => "email has already been taken",
+                 "type" => "error"
+               },
+               %{
+                 "code" => 409,
+                 "data" => %{
+                   "email" => "newuser@pleroma.social",
+                   "nickname" => "newuser"
+                 },
+                 "error" => "",
+                 "type" => "error"
+               }
+             ]
+
+      assert User.get_by_nickname("newuser") === nil
+    end
   end
 
   describe "/api/pleroma/admin/users/:nickname" do