Fix dashboard APIs return (#6177)

* fix(dashboard_api): delete non-exist user wrongly return 204

* fix(dashboard): dashboard user should use `tags` not `tag`

* fix(dashboard): create/update user return 200 with full users list

* fix(dashboard): logout status code 204

* fix(dashboard): update pwd status code 204

* test: test suite for dashboard APIs

* refactor(dashboard): user info mnesia record name use description

* style: make elvis happy

* fix(api): dashboard swagger check request should not override env

* fix(dashboard): add/modify dashboard returns single record

* ci: update emqx-fvt version to new tag 1.0.2-dev1
This commit is contained in:
JimMoen 2021-11-18 14:36:12 +08:00 committed by GitHub
parent 14da850e06
commit e361cd5733
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 199 additions and 138 deletions

View File

@ -61,7 +61,7 @@ jobs:
- uses: actions/checkout@v2
with:
repository: emqx/emqx-fvt
ref: v1.5.0
ref: 1.0.2-dev1
path: .
- uses: actions/setup-java@v1
with:

View File

@ -19,14 +19,14 @@
-include_lib("common_test/include/ct.hrl").
-export([ request_api/3
, request_api/4
, request_api/5
, get_http_data/1
, create_default_app/0
, delete_default_app/0
, default_auth_header/0
, auth_header/2
]).
, request_api/4
, request_api/5
, get_http_data/1
, create_default_app/0
, delete_default_app/0
, default_auth_header/0
, auth_header/2
]).
request_api(Method, Url, Auth) ->
request_api(Method, Url, [], Auth, []).
@ -57,15 +57,14 @@ do_request_api(Method, Request, HttpOpts) ->
case httpc:request(Method, Request, HttpOpts, [{body_format, binary}]) of
{error, socket_closed_remotely} ->
{error, socket_closed_remotely};
{ok, {{"HTTP/1.1", Code, _}, _Headers, Return} }
when Code =:= 200 orelse Code =:= 201 ->
{ok, Return};
{ok, {{"HTTP/1.1", Code, _}, _Headers, Return} } ->
{ok, Code, Return};
{ok, {Reason, _, _}} ->
{error, Reason}
end.
get_http_data(ResponseBody) ->
maps:get(<<"data">>, emqx_json:decode(ResponseBody, [return_maps])).
emqx_json:decode(ResponseBody, [return_maps]).
auth_header(User, Pass) ->
Encoded = base64:encode_to_string(lists:append([User,":",Pass])),

View File

@ -18,7 +18,7 @@
-record(?ADMIN, {
username :: binary(),
pwdhash :: binary(),
tags :: list() | binary(),
description :: binary(),
role = undefined :: atom(),
extra = [] :: term() %% not used so far, for future extension
}).

View File

@ -40,7 +40,7 @@ start_listeners() ->
Authorization = {?MODULE, authorize_appid},
GlobalSpec = #{
openapi => "3.0.0",
info => #{title => "EMQ X Dashboard API", version => "5.0.0"},
info => #{title => "EMQ X API", version => "5.0.0"},
servers => [#{url => ?BASE_PATH}],
components => #{
schemas => #{},

View File

@ -19,6 +19,7 @@
-module(emqx_dashboard_admin).
-include("emqx_dashboard.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-boot_mnesia({mnesia, [boot]}).
@ -63,17 +64,17 @@ mnesia(boot) ->
%% API
%%--------------------------------------------------------------------
-spec(add_user(binary(), binary(), binary()) -> ok | {error, any()}).
add_user(Username, Password, Tags) when is_binary(Username), is_binary(Password) ->
Admin = #?ADMIN{username = Username, pwdhash = hash(Password), tags = Tags},
return(mria:transaction(?DASHBOARD_SHARD, fun add_user_/1, [Admin])).
-spec(add_user(binary(), binary(), binary()) -> {ok, map()} | {error, any()}).
add_user(Username, Password, Desc)
when is_binary(Username), is_binary(Password) ->
return(mria:transaction(?DASHBOARD_SHARD, fun add_user_/3, [Username, Password, Desc])).
%% black-magic: force overwrite a user
force_add_user(Username, Password, Tags) ->
force_add_user(Username, Password, Desc) ->
AddFun = fun() ->
mnesia:write(#?ADMIN{username = Username,
pwdhash = hash(Password),
tags = Tags})
description = Desc})
end,
case mria:transaction(?DASHBOARD_SHARD, AddFun) of
{atomic, ok} -> ok;
@ -81,33 +82,38 @@ force_add_user(Username, Password, Tags) ->
end.
%% @private
add_user_(Admin = #?ADMIN{username = Username}) ->
add_user_(Username, Password, Desc) ->
case mnesia:wread({?ADMIN, Username}) of
[] -> mnesia:write(Admin);
[_] -> mnesia:abort(<<"Username Already Exist">>)
[] ->
Admin = #?ADMIN{username = Username, pwdhash = hash(Password), description = Desc},
mnesia:write(Admin),
#{username => Username, description => Desc};
[_] ->
mnesia:abort(<<"Username Already Exist">>)
end.
-spec(remove_user(binary()) -> ok | {error, any()}).
-spec(remove_user(binary()) -> {ok, any()} | {error, any()}).
remove_user(Username) when is_binary(Username) ->
Trans = fun() ->
case lookup_user(Username) of
[] ->
mnesia:abort(<<"Username Not Found">>);
_ -> ok
end,
mnesia:delete({?ADMIN, Username})
[] -> mnesia:abort(<<"Username Not Found">>);
_ -> mnesia:delete({?ADMIN, Username})
end
end,
return(mria:transaction(?DASHBOARD_SHARD, Trans)).
-spec(update_user(binary(), binary()) -> ok | {error, term()}).
update_user(Username, Tags) when is_binary(Username) ->
return(mria:transaction(?DASHBOARD_SHARD, fun update_user_/2, [Username, Tags])).
-spec(update_user(binary(), binary()) -> {ok, map()} | {error, term()}).
update_user(Username, Desc) when is_binary(Username) ->
return(mria:transaction(?DASHBOARD_SHARD, fun update_user_/2, [Username, Desc])).
%% @private
update_user_(Username, Tags) ->
update_user_(Username, Desc) ->
case mnesia:wread({?ADMIN, Username}) of
[] -> mnesia:abort(<<"Username Not Found">>);
[Admin] -> mnesia:write(Admin#?ADMIN{tags = Tags})
[] ->
mnesia:abort(<<"Username Not Found">>);
[Admin] ->
mnesia:write(Admin#?ADMIN{description = Desc}),
#{username => Username, description => Desc}
end.
change_password(Username, OldPasswd, NewPasswd) when is_binary(Username) ->
@ -146,17 +152,15 @@ lookup_user(Username) when is_binary(Username) ->
-spec(all_users() -> [map()]).
all_users() ->
lists:map(fun(#?ADMIN{username = Username,
tags = Tags
description = Desc
}) ->
#{username => Username,
%% named tag but not tags, for unknown reason
%% TODO: fix this comment
tag => Tags
description => Desc
}
end, ets:tab2list(?ADMIN)).
return({atomic, _}) ->
ok;
return({atomic, Result}) ->
{ok, Result};
return({aborted, Reason}) ->
{error, Reason}.
@ -219,5 +223,5 @@ add_default_user(Username, Password) when ?EMPTY_KEY(Username) orelse ?EMPTY_KEY
add_default_user(Username, Password) ->
case lookup_user(Username) of
[] -> add_user(Username, Password, <<"administrator">>);
_ -> ok
_ -> {ok, default_user_exists}
end.

View File

@ -37,14 +37,21 @@
-define(EMPTY(V), (V == undefined orelse V == <<>>)).
-define(ERROR_USERNAME_OR_PWD, 'ERROR_USERNAME_OR_PWD').
-define(USER_NOT_FOUND_BODY, #{ code => <<"USER_NOT_FOUND">>
, message => <<"User not found">>}).
namespace() -> "dashboard".
api_spec() ->
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
paths() -> ["/login", "/logout", "/users",
"/users/:username", "/users/:username/change_pwd"].
paths() ->
[ "/login"
, "/logout"
, "/users"
, "/users/:username"
, "/users/:username/change_pwd"].
schema("/login") ->
#{
@ -53,8 +60,7 @@ schema("/login") ->
tags => [<<"dashboard">>],
description => <<"Dashboard Auth">>,
summary => <<"Dashboard Auth">>,
'requestBody' =>
[
'requestBody' => [
{username, mk(binary(),
#{desc => <<"The User for which to create the token.">>,
'maxLength' => 100, example => <<"admin">>})},
@ -67,10 +73,12 @@ schema("/login") ->
{license, [{edition,
mk(enum([community, enterprise]), #{desc => <<"license">>,
example => "community"})}]},
{version, mk(string(), #{desc => <<"version">>, example => <<"5.0.0">>})}],
{version, mk(string(), #{desc => <<"version">>, example => <<"5.0.0">>})}
],
401 => [
{code, mk(string(), #{example => 'ERROR_USERNAME_OR_PWD'})},
{message, mk(string(), #{example => "Unauthorized"})}]
{message, mk(string(), #{example => "Unauthorized"})}
]
},
security => []
}};
@ -86,7 +94,7 @@ schema("/logout") ->
'maxLength' => 100, example => <<"admin">>})}
],
responses => #{
200 => <<"Dashboard logout successfully">>
204 => <<"Dashboard logout successfully">>
}
}
};
@ -95,10 +103,10 @@ schema("/users") ->
'operationId' => users,
get => #{
tags => [<<"dashboard">>],
description => <<"Get dashboard users">>,
description => <<"Get dashboard users list">>,
responses => #{
200 => mk(array(ref(?MODULE, user)),
#{desc => "User lists"})
200 => mk( array(ref(?MODULE, user))
, #{desc => "User lists"})
}
},
post => #{
@ -106,9 +114,12 @@ schema("/users") ->
description => <<"Create dashboard users">>,
'requestBody' => fields(user_password),
responses => #{
200 => <<"Create user successfully">>,
200 => mk( ref(?MODULE, user)
, #{desc => <<"Create User successfully">>}),
400 => [{code, mk(string(), #{example => 'CREATE_FAIL'})},
{message, mk(string(), #{example => "Create user failed"})}]}
{message, mk(string(), #{example => "Create user failed"})}
]
}
}
};
@ -120,11 +131,20 @@ schema("/users/:username") ->
description => <<"Update dashboard users">>,
parameters => [{username, mk(binary(),
#{in => path, example => <<"admin">>})}],
'requestBody' => [{tag, mk(binary(), #{desc => <<"Tag">>})}],
'requestBody' => [
{ description
, mk(binary(), #{desc => <<"User description">>, example => <<"administrator">>})}
],
responses => #{
200 => <<"Update User successfully">>,
400 => [{code, mk(string(), #{example => 'UPDATE_FAIL'})},
{message, mk(string(), #{example => "Update Failed unknown"})}]}},
200 => mk( ref(?MODULE, user)
, #{desc => <<"Update User successfully">>}),
400 => [
{code, mk(string(), #{example => 'UPDATE_FAIL'})},
{message, mk(string(), #{example => "Update Failed unknown"})}
],
404 => emqx_dashboard_swagger:error_codes(['USER_NOT_FOUND'], <<"User Not Found">>)
}
},
delete => #{
tags => [<<"dashboard">>],
description => <<"Delete dashboard users">>,
@ -134,7 +154,11 @@ schema("/users/:username") ->
204 => <<"Delete User successfully">>,
400 => [
{code, mk(string(), #{example => 'CANNOT_DELETE_ADMIN'})},
{message, mk(string(), #{example => "CANNOT DELETE ADMIN"})}]}}
{message, mk(string(), #{example => "CANNOT DELETE ADMIN"})}
],
404 => emqx_dashboard_swagger:error_codes(['USER_NOT_FOUND'], <<"User Not Found">>)
}
}
};
schema("/users/:username/change_pwd") ->
#{
@ -149,23 +173,26 @@ schema("/users/:username/change_pwd") ->
{new_pwd, mk(binary(), #{required => true})}
],
responses => #{
200 => <<"Update user password successfully">>,
204 => <<"Update user password successfully">>,
400 => [
{code, mk(string(), #{example => 'UPDATE_FAIL'})},
{message, mk(string(), #{example => "Failed Reason"})}]}}
{message, mk(string(), #{example => "Failed Reason"})}
]
}
}
}.
fields(user) ->
[
{tag,
{description,
mk(binary(),
#{desc => <<"tag">>, example => "administrator"})},
#{desc => <<"User description">>, example => "administrator"})},
{username,
mk(binary(),
#{desc => <<"username">>, example => "emqx"})}
];
fields(user_password) ->
fields(user) ++ [{password, mk(binary(), #{desc => "Password"})}].
fields(user) ++ [{password, mk(binary(), #{desc => "Password", example => <<"public">>})}].
login(post, #{body := Params}) ->
Username = maps:get(<<"username">>, Params),
@ -182,7 +209,7 @@ logout(_, #{body := #{<<"username">> := Username},
headers := #{<<"authorization">> := <<"Bearer ", Token/binary>>}}) ->
case emqx_dashboard_admin:destroy_token_by_username(Username, Token) of
ok ->
200;
204;
_R ->
{401, 'BAD_TOKEN_OR_USERNAME', <<"Ensure your token & username">>}
end.
@ -191,7 +218,7 @@ users(get, _Request) ->
{200, emqx_dashboard_admin:all_users()};
users(post, #{body := Params}) ->
Tag = maps:get(<<"tag">>, Params),
Desc = maps:get(<<"description">>, Params),
Username = maps:get(<<"username">>, Params),
Password = maps:get(<<"password">>, Params),
case ?EMPTY(Username) orelse ?EMPTY(Password) of
@ -199,35 +226,43 @@ users(post, #{body := Params}) ->
{400, #{code => <<"CREATE_USER_FAIL">>,
message => <<"Username or password undefined">>}};
false ->
case emqx_dashboard_admin:add_user(Username, Password, Tag) of
ok -> {200};
case emqx_dashboard_admin:add_user(Username, Password, Desc) of
{ok, Result} ->
{200, Result};
{error, Reason} ->
{400, #{code => <<"CREATE_USER_FAIL">>, message => Reason}}
end
end.
user(put, #{bindings := #{username := Username}, body := Params}) ->
Tag = maps:get(<<"tag">>, Params),
case emqx_dashboard_admin:update_user(Username, Tag) of
ok -> {200};
{error, Reason} ->
{400, #{code => <<"UPDATE_FAIL">>, message => Reason}}
Desc = maps:get(<<"description">>, Params),
case emqx_dashboard_admin:update_user(Username, Desc) of
{ok, Result} ->
{200, Result};
{error, _Reason} ->
{404, ?USER_NOT_FOUND_BODY}
end;
user(delete, #{bindings := #{username := Username}}) ->
case Username == <<"admin">> of
true -> {400, #{code => <<"CANNOT_DELETE_ADMIN">>,
message => <<"Cannot delete admin">>}};
true ->
{400, #{code => <<"ACTION_NOT_ALLOWED">>,
message => <<"Cannot delete admin">>}};
false ->
_ = emqx_dashboard_admin:remove_user(Username),
{204}
case emqx_dashboard_admin:remove_user(Username) of
{error, _Reason} ->
{404, ?USER_NOT_FOUND_BODY};
{ok, _} ->
{204}
end
end.
change_pwd(put, #{bindings := #{username := Username}, body := Params}) ->
OldPwd = maps:get(<<"old_pwd">>, Params),
NewPwd = maps:get(<<"new_pwd">>, Params),
case emqx_dashboard_admin:change_password(Username, OldPwd, NewPwd) of
ok -> {200};
{ok, _} ->
{204};
{error, Reason} ->
{400, #{code => <<"CHANGE_PWD_FAIL">>, message => Reason}}
end.

View File

@ -29,7 +29,7 @@ start(_StartType, _StartArgs) ->
ok = mria_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
_ = emqx_dashboard:start_listeners(),
emqx_dashboard_cli:load(),
ok = emqx_dashboard_admin:add_default_user(),
{ok, _Result} = emqx_dashboard_admin:add_default_user(),
{ok, Sup}.
stop(_State) ->

View File

@ -27,9 +27,9 @@ load() ->
admins(["add", Username, Password]) ->
admins(["add", Username, Password, ""]);
admins(["add", Username, Password, Tag]) ->
case emqx_dashboard_admin:add_user(bin(Username), bin(Password), bin(Tag)) of
ok ->
admins(["add", Username, Password, Desc]) ->
case emqx_dashboard_admin:add_user(bin(Username), bin(Password), bin(Desc)) of
{ok, _} ->
emqx_ctl:print("ok~n");
{error, already_existed} ->
emqx_ctl:print("Error: already existed~n");
@ -46,9 +46,10 @@ admins(["del", Username]) ->
emqx_ctl:print("~p~n", [Status]);
admins(_) ->
emqx_ctl:usage([{"admins add <Username> <Password> <Tags>", "Add dashboard user"},
{"admins passwd <Username> <Password>", "Reset dashboard user password"},
{"admins del <Username>", "Delete dashboard user" }]).
emqx_ctl:usage(
[{"admins add <Username> <Password> <Description>", "Add dashboard user"},
{"admins passwd <Username> <Password>", "Reset dashboard user password"},
{"admins del <Username>", "Delete dashboard user" }]).
unload() ->
emqx_ctl:unregister_command(admins).

View File

@ -213,7 +213,7 @@ check_request_body(#{body := Body}, Schema, Module, CheckFun, true) ->
check_request_body(#{body := Body}, Spec, _Module, CheckFun, false) ->
lists:foldl(fun({Name, Type}, Acc) ->
Schema = ?INIT_SCHEMA#{roots => [{Name, Type}]},
maps:merge(Acc, CheckFun(Schema, Body, #{}))
maps:merge(Acc, CheckFun(Schema, Body, #{override_env => false}))
end, #{}, Spec).
%% tags, description, summary, security, deprecated

View File

@ -31,11 +31,14 @@
-define(CONTENT_TYPE, "application/x-www-form-urlencoded").
-define(HOST, "http://127.0.0.1:18083/").
-define(HOST, "http://127.0.0.1:18083").
-define(API_VERSION, "v4").
%% -define(API_VERSION, "v5").
-define(BASE_PATH, "api").
-define(BASE_PATH, "/api/v5").
-define(APP_DASHBOARD, emqx_dashboard).
-define(APP_MANAGEMENT, emqx_management).
-define(OVERVIEWS, ['alarms/activated',
'alarms/deactivated',
@ -51,9 +54,24 @@
]).
all() ->
%% TODO: V5 API
% emqx_common_test_helpers:all(?MODULE).
[t_cli, t_lookup_by_username_jwt, t_clean_expired_jwt].
%% TODO: V5 API
%% emqx_common_test_helpers:all(?MODULE).
[t_cli, t_lookup_by_username_jwt, t_clean_expired_jwt, t_rest_api].
init_suite() ->
init_suite([]).
init_suite(Apps) ->
mria:start(),
application:load(emqx_management),
emqx_common_test_helpers:start_apps(Apps ++ [emqx_dashboard], fun set_special_configs/1).
end_suite() ->
end_suite([]).
end_suite(Apps) ->
application:unload(emqx_management),
emqx_common_test_helpers:stop_apps(Apps ++ [emqx_dashboard]).
init_per_suite(Config) ->
emqx_common_test_helpers:start_apps([emqx_management, emqx_dashboard],
@ -66,23 +84,32 @@ end_per_suite(_Config) ->
set_special_configs(emqx_management) ->
Listeners = [#{protocol => http, port => 8081}],
emqx_config:put([emqx_management], #{listeners => Listeners,
applications =>[#{id => "admin", secret => "public"}]}),
Config = #{listeners => Listeners,
applications => [#{id => "admin", secret => "public"}]},
emqx_config:put([emqx_management], Config),
ok;
set_special_configs(emqx_dashboard) ->
Listeners = [#{protocol => http, port => 18083}],
Config = #{listeners => Listeners,
default_username => <<"admin">>,
default_password => <<"public">>
},
emqx_config:put([emqx_dashboard], Config),
ok;
set_special_configs(_) ->
ok.
t_overview(_) ->
mnesia:clear_table(?ADMIN),
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"tag">>),
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"simple_description">>),
[?assert(request_dashboard(get, api_path(erlang:atom_to_list(Overview)),
auth_header_()))|| Overview <- ?OVERVIEWS].
auth_header_())) || Overview <- ?OVERVIEWS].
t_admins_add_delete(_) ->
mnesia:clear_table(?ADMIN),
Tag = <<"tag">>,
ok = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, Tag),
ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, Tag),
Desc = <<"simple description">>,
ok = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, Desc),
ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, Desc),
Admins = emqx_dashboard_admin:all_users(),
?assertEqual(2, length(Admins)),
ok = emqx_dashboard_admin:remove_user(<<"username1">>),
@ -92,7 +119,7 @@ t_admins_add_delete(_) ->
<<"password">>,
<<"pwd">>),
timer:sleep(10),
Header = auth_header_("username", "pwd"),
Header = auth_header_(<<"username">>, <<"pwd">>),
?assert(request_dashboard(get, api_path("brokers"), Header)),
ok = emqx_dashboard_admin:remove_user(<<"username">>),
@ -100,28 +127,22 @@ t_admins_add_delete(_) ->
t_rest_api(_Config) ->
mnesia:clear_table(?ADMIN),
Tag = <<"administrator">>,
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, Tag),
{ok, Res0} = http_get("users"),
Desc = <<"administrator">>,
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, Desc),
{ok, 200, Res0} = http_get(["users"]),
?assertEqual([#{<<"username">> => <<"admin">>,
<<"tags">> => <<"administrator">>}], get_http_data(Res0)),
AssertSuccess = fun({ok, Res}) ->
?assertEqual(#{<<"code">> => 0}, json(Res))
end,
[AssertSuccess(R)
|| R <- [ http_put("users/admin", #{<<"tags">> => <<"a_new_tag">>})
, http_post("users", #{<<"username">> => <<"usera">>,
<<"password">> => <<"passwd">>})
, http_post("auth", #{<<"username">> => <<"usera">>,
<<"password">> => <<"passwd">>})
, http_delete("users/usera")
, http_put("users/admin/change_pwd", #{<<"old_pwd">> => <<"public">>,
<<"new_pwd">> => <<"newpwd">>})
, http_post("auth", #{<<"username">> => <<"admin">>,
<<"password">> => <<"newpwd">>})
]],
<<"description">> => <<"administrator">>}], get_http_data(Res0)),
{ok, 200, _} = http_put(["users", "admin"], #{<<"description">> => <<"a_new_description">>}),
{ok, 200, _} = http_post(["users"], #{<<"username">> => <<"usera">>,
<<"password">> => <<"passwd">>,
<<"description">> => Desc}),
{ok, 204, _} = http_delete(["users", "usera"]),
{ok, 404, _} = http_delete(["users", "usera"]),
{ok, 204, _} = http_put( ["users", "admin", "change_pwd"]
, #{<<"old_pwd">> => <<"public">>,
<<"new_pwd">> => <<"newpwd">>}),
mnesia:clear_table(?ADMIN),
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"administrator">>),
ok.
t_cli(_Config) ->
@ -175,17 +196,17 @@ bin(X) -> iolist_to_binary(X).
random_num() ->
erlang:system_time(nanosecond).
http_get(Path) ->
request_api(get, api_path(Path), auth_header_()).
http_get(Parts) ->
request_api(get, api_path(Parts), auth_header_()).
http_delete(Path) ->
request_api(delete, api_path(Path), auth_header_()).
http_delete(Parts) ->
request_api(delete, api_path(Parts), auth_header_()).
http_post(Path, Body) ->
request_api(post, api_path(Path), [], auth_header_(), Body).
http_post(Parts, Body) ->
request_api(post, api_path(Parts), [], auth_header_(), Body).
http_put(Path, Body) ->
request_api(put, api_path(Path), [], auth_header_(), Body).
http_put(Parts, Body) ->
request_api(put, api_path(Parts), [], auth_header_(), Body).
request_dashboard(Method, Url, Auth) ->
Request = {Url, [Auth]},
@ -198,21 +219,22 @@ do_request_dashboard(Method, Request)->
case httpc:request(Method, Request, [], []) of
{error, socket_closed_remotely} ->
{error, socket_closed_remotely};
{ok, {{"HTTP/1.1", 200, _}, _, _Return} } ->
true;
{ok, {{"HTTP/1.1", Code, _}, _Headers, Return} }
when Code >= 200 andalso Code =< 299 ->
{ok, Return};
{ok, {Reason, _, _}} ->
{error, Reason}
end.
auth_header_() ->
auth_header_("admin", "public").
auth_header_(<<"admin">>, <<"public">>).
auth_header_(User, Pass) ->
Encoded = base64:encode_to_string(lists:append([User,":",Pass])),
{"Authorization","Basic " ++ Encoded}.
auth_header_(Username, Password) ->
{ok, Token} = emqx_dashboard_admin:sign_token(Username, Password),
{"Authorization","Bearer " ++ binary_to_list(Token)}.
api_path(Path) ->
?HOST ++ filename:join([?BASE_PATH, ?API_VERSION, Path]).
api_path(Parts) ->
?HOST ++ filename:join([?BASE_PATH | Parts]).
json(Data) ->
{ok, Jsx} = emqx_json:safe_decode(Data, [return_maps]), Jsx.