浏览代码

Merge pull request #12421 from HJianBo/fix-import-users

fix(user_import): ensure the last record overwrites previous one
JianBo He 2 年之前
父节点
当前提交
c0674913e2

+ 10 - 2
apps/emqx_auth/src/emqx_authn/emqx_authn_user_import_api.erl

@@ -96,8 +96,16 @@ request_body_schema() ->
                 schema => #{
                     type => object,
                     example => [
-                        #{<<"user_id">> => <<"user1">>, <<"password">> => <<"password1">>},
-                        #{<<"user_id">> => <<"user2">>, <<"password">> => <<"password2">>}
+                        #{
+                            <<"user_id">> => <<"user1">>,
+                            <<"password">> => <<"password1">>,
+                            <<"is_superuser">> => true
+                        },
+                        #{
+                            <<"user_id">> => <<"user2">>,
+                            <<"password">> => <<"password2">>,
+                            <<"is_superuser">> => false
+                        }
                     ]
                 }
             }

+ 3 - 0
apps/emqx_auth/test/data/user-credentials-plain-dup.csv

@@ -0,0 +1,3 @@
+user_id,password,is_superuser
+myuser3,password3,true
+myuser3,password4,false

+ 12 - 0
apps/emqx_auth/test/data/user-credentials-plain-dup.json

@@ -0,0 +1,12 @@
+[
+    {
+        "user_id":"myuser1",
+        "password":"password1",
+        "is_superuser": true
+    },
+    {
+        "user_id":"myuser1",
+        "password":"password2",
+        "is_superuser": false
+    }
+]

+ 1 - 1
apps/emqx_auth_mnesia/src/emqx_authn_mnesia.erl

@@ -457,7 +457,7 @@ parse_import_users(Filename, FileData, Convertor) ->
         end
     end,
     ReaderFn = reader_fn(Filename, FileData),
-    Users = lists:reverse(Eval(ReaderFn)),
+    Users = Eval(ReaderFn),
     NewUsersCount =
         lists:foldl(
             fun(

+ 49 - 0
apps/emqx_auth_mnesia/test/emqx_authn_mnesia_SUITE.erl

@@ -340,6 +340,55 @@ t_import_users_prepared_list(_) ->
         )
     ).
 
+t_import_users_duplicated_records(_) ->
+    Config0 = config(),
+    Config = Config0#{password_hash_algorithm => #{name => plain, salt_position => disable}},
+    {ok, State} = emqx_authn_mnesia:create(?AUTHN_ID, Config),
+
+    ?assertEqual(
+        ok,
+        emqx_authn_mnesia:import_users(
+            sample_filename_and_data(plain, <<"user-credentials-plain-dup.json">>),
+            State
+        )
+    ),
+    ?assertEqual(
+        ok,
+        emqx_authn_mnesia:import_users(
+            sample_filename_and_data(plain, <<"user-credentials-plain-dup.csv">>),
+            State
+        )
+    ),
+    Users1 = [
+        #{
+            <<"user_id">> => <<"myuser5">>,
+            <<"password">> => <<"password5">>,
+            <<"is_superuser">> => true
+        },
+        #{
+            <<"user_id">> => <<"myuser5">>,
+            <<"password">> => <<"password6">>,
+            <<"is_superuser">> => false
+        }
+    ],
+    ?assertEqual(
+        ok,
+        emqx_authn_mnesia:import_users(
+            {plain, prepared_user_list, Users1},
+            State
+        )
+    ),
+
+    %% assert: the last record overwrites the previous one
+    ?assertMatch(
+        [
+            {user_info, {_, <<"myuser1">>}, <<"password2">>, _, false},
+            {user_info, {_, <<"myuser3">>}, <<"password4">>, _, false},
+            {user_info, {_, <<"myuser5">>}, <<"password6">>, _, false}
+        ],
+        ets:tab2list(emqx_authn_mnesia)
+    ).
+
 %%------------------------------------------------------------------------------
 %% Helpers
 %%------------------------------------------------------------------------------

+ 6 - 8
apps/emqx_management/src/emqx_mgmt_api_cluster.erl

@@ -206,11 +206,10 @@ fields(node_invitation_succeed) ->
         [
             {finished_at,
                 ?HOCON(
-                    emqx_utils_calendar:epoch_millisecond(),
+                    binary(),
                     #{
-                        desc =>
-                            <<"The time of the async invitation result is received, millisecond precision epoch">>,
-                        example => <<"1705044829915">>
+                        desc => <<"The time of the async invitation result is received">>,
+                        example => <<"2024-01-30T15:24:39.355+08:00">>
                     }
                 )}
         ];
@@ -223,11 +222,10 @@ fields(node_invitation_in_progress) ->
             )},
         {started_at,
             ?HOCON(
-                emqx_utils_calendar:epoch_millisecond(),
+                binary(),
                 #{
-                    desc =>
-                        <<"The start timestamp of the invitation, millisecond precision epoch">>,
-                    example => <<"1705044829915">>
+                    desc => <<"The time of the async invitation is started">>,
+                    example => <<"2024-01-30T15:24:39.355+08:00">>
                 }
             )}
     ].