From eac94201701a849771e06cebcb222f0a3d0c36c8 Mon Sep 17 00:00:00 2001 From: Turtle Date: Mon, 26 Jul 2021 13:57:52 +0800 Subject: [PATCH] feat(dashboard): Support swagger dashboard API --- apps/emqx_dashboard/etc/emqx_dashboard.conf | 4 +- .../emqx_dashboard/src/emqx_dashboard_api.erl | 279 +++++++++++++----- 2 files changed, 207 insertions(+), 76 deletions(-) diff --git a/apps/emqx_dashboard/etc/emqx_dashboard.conf b/apps/emqx_dashboard/etc/emqx_dashboard.conf index b94c4f50c..de453c12c 100644 --- a/apps/emqx_dashboard/etc/emqx_dashboard.conf +++ b/apps/emqx_dashboard/etc/emqx_dashboard.conf @@ -1,5 +1,5 @@ ##-------------------------------------------------------------------- -## Dashboard for EMQ X +## EMQ X Dashboard ##-------------------------------------------------------------------- emqx_dashboard:{ @@ -20,7 +20,7 @@ emqx_dashboard:{ ## , ## { ## protocol: https -## port: 8081 +## port: 18084 ## acceptors: 2 ## backlog: 512 ## send_timeout: 15s diff --git a/apps/emqx_dashboard/src/emqx_dashboard_api.erl b/apps/emqx_dashboard/src/emqx_dashboard_api.erl index 653380ab6..f11d6588b 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_api.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_api.erl @@ -16,95 +16,226 @@ -module(emqx_dashboard_api). +-behaviour(minirest_api). + -include("emqx_dashboard.hrl"). --rest_api(#{name => auth_user, - method => 'POST', - path => "/auth", - func => auth, - descr => "Authenticate an user" - }). +-import(emqx_mgmt_util, [ response_schema/1 + , response_schema/2 + , request_body_schema/1 + , response_array_schema/2 + ]). --rest_api(#{name => create_user, - method => 'POST', - path => "/users/", - func => create, - descr => "Create an user" - }). +-export([api_spec/0]). --rest_api(#{name => list_users, - method => 'GET', - path => "/users/", - func => list, - descr => "List users" - }). - --rest_api(#{name => update_user, - method => 'PUT', - path => "/users/:bin:name", - func => update, - descr => "Update an user" - }). - --rest_api(#{name => delete_user, - method => 'DELETE', - path => "/users/:bin:name", - func => delete, - descr => "Delete an user" - }). - --rest_api(#{name => change_pwd, - method => 'PUT', - path => "/change_pwd/:bin:username", - func => change_pwd, - descr => "Change password for an user" - }). - --export([ list/2 - , create/2 - , update/2 - , delete/2 - , auth/2 +-export([ auth/2 + , users/2 + , user/2 , change_pwd/2 ]). +api_spec() -> + {[auth_api(), users_api(), user_api(), change_pwd_api()], schemas()}. + +schemas() -> + [#{auth => #{ + type => object, + properties => #{ + username => #{ + type => string, + description => <<"Username">>}, + password => #{ + type => string, + description => <<"password">>} + } + }}, + #{show_user => #{ + type => object, + properties => #{ + username => #{ + type => string, + description => <<"Username">>}, + tag => #{ + type => string, + description => <<"Tag">>} + } + }}, + #{create_user => #{ + type => object, + properties => #{ + username => #{ + type => string, + description => <<"Username">>}, + password => #{ + type => string, + description => <<"Password">>}, + tag => #{ + type => string, + description => <<"Tag">>} + } + }}]. + +auth_api() -> + Metadata = #{ + post => #{ + description => <<"Dashboard Auth">>, + 'requestBody' => request_body_schema(auth), + responses => #{ + <<"200">> => + response_schema(<<"Dashboard Auth successfully">>), + <<"400">> => bad_request() + }, + security => [] + } + }, + {"/auth", Metadata, auth}. + +users_api() -> + Metadata = #{ + get => #{ + description => <<"Get dashboard users">>, + responses => #{ + <<"200">> => response_array_schema(<<"">>, show_user) + } + } + }, + {"/users", Metadata, users}. + +user_api() -> + Metadata = #{ + delete => #{ + description => <<"Delete dashboard users">>, + responses => #{ + <<"200">> => response_schema(<<"Delete User successfully">>), + <<"400">> => bad_request() + } + }, + put => #{ + description => <<"Update dashboard users">>, + 'requestBody' => request_body_schema(#{ + type => object, + properties => #{ + tags => #{ + type => string + } + } + }), + responses => #{ + <<"200">> => response_schema(<<"Update Users successfully">>), + <<"400">> => bad_request() + } + }, + post => #{ + description => <<"Create dashboard users">>, + 'requestBody' => request_body_schema(create_user), + responses => #{ + <<"200">> => response_schema(<<"Create Users successfully">>), + <<"400">> => bad_request() + } + } + }, + {"/users/:username", Metadata, user}. + +change_pwd_api() -> + Metadata = #{ + put => #{ + description => <<"Update dashboard users password">>, + 'requestBody' => request_body_schema(#{ + type => object, + properties => #{ + old_pwd => #{ + type => string + }, + new_pwd => #{ + type => string + } + } + }), + responses => #{ + <<"200">> => response_schema(<<"Update Users password successfully">>), + <<"400">> => bad_request() + } + } + }, + {"/change_pwd/:username", Metadata, change_pwd}. + -define(EMPTY(V), (V == undefined orelse V == <<>>)). -auth(_Bindings, Params) -> - Username = proplists:get_value(<<"username">>, Params), - Password = proplists:get_value(<<"password">>, Params), - return(emqx_dashboard_admin:check(Username, Password)). +auth(post, Request) -> + {ok, Body, _} = cowboy_req:read_body(Request), + Params = emqx_json:decode(Body, [return_maps]), + Username = maps:get(<<"username">>, Params), + Password = maps:get(<<"password">>, Params), + case emqx_dashboard_admin:check(Username, Password) of + ok -> + {200}; + {error, Reason} -> + {400, #{code => <<"AUTH_FAIL">>, message => Reason}} + end. -change_pwd(#{username := Username}, Params) -> - OldPwd = proplists:get_value(<<"old_pwd">>, Params), - NewPwd = proplists:get_value(<<"new_pwd">>, Params), - return(emqx_dashboard_admin:change_password(Username, OldPwd, NewPwd)). +users(get, _Request) -> + {200, [row(User) || User <- emqx_dashboard_admin:all_users()]}. -create(_Bindings, Params) -> - Username = proplists:get_value(<<"username">>, Params), - Password = proplists:get_value(<<"password">>, Params), - Tags = proplists:get_value(<<"tags">>, Params), - return(case ?EMPTY(Username) orelse ?EMPTY(Password) of - true -> {error, <<"Username or password undefined">>}; - false -> emqx_dashboard_admin:add_user(Username, Password, Tags) - end). +user(put, Request) -> + Username = cowboy_req:binding(username, Request), + {ok, Body, _} = cowboy_req:read_body(Request), + Params = emqx_json:decode(Body, [return_maps]), + Tags = maps:get(<<"tags">>, Params), + case emqx_dashboard_admin:update_user(Username, Tags) of + ok -> {200}; + {error, Reason} -> + {400, #{code => <<"UPDATE_FAIL">>, message => Reason}} + end; -list(_Bindings, _Params) -> - return({ok, [row(User) || User <- emqx_dashboard_admin:all_users()]}). +user(delete, Request) -> + Username = cowboy_req:binding(username, Request), + case Username == <<"admin">> of + true -> {400, #{code => <<"CONNOT_DELETE_ADMIN">>, + message => <<"Cannot delete admin">>}}; + false -> + _ = emqx_dashboard_admin:remove_user(Username), + {200} + end; -update(#{name := Username}, Params) -> - Tags = proplists:get_value(<<"tags">>, Params), - return(emqx_dashboard_admin:update_user(Username, Tags)). +user(post, Request) -> + {ok, Body, _} = cowboy_req:read_body(Request), + Params = emqx_json:decode(Body, [return_maps]), + Tags = maps:get(<<"tags">>, Params), + Username = maps:get(<<"username">>, Params), + Password = maps:get(<<"password">>, Params), + case ?EMPTY(Username) orelse ?EMPTY(Password) of + true -> + {400, #{code => <<"CREATE_USER_FAIL">>, + message => <<"Username or password undefined">>}}; + false -> + case emqx_dashboard_admin:add_user(Username, Password, Tags) of + ok -> {200}; + {error, Reason} -> + {400, #{code => <<"CREATE_USER_FAIL">>, message => Reason}} + end + end. -delete(#{name := <<"admin">>}, _Params) -> - return({error, <<"Cannot delete admin">>}); - -delete(#{name := Username}, _Params) -> - return(emqx_dashboard_admin:remove_user(Username)). +change_pwd(put, Request) -> + Username = cowboy_req:binding(username, Request), + {ok, Body, _} = cowboy_req:read_body(Request), + Params = emqx_json:decode(Body, [return_maps]), + OldPwd = maps:get(<<"old_pwd">>, Params), + NewPwd = maps:get(<<"new_pwd">>, Params), + case emqx_dashboard_admin:change_password(Username, OldPwd, NewPwd) of + ok -> {200}; + {error, Reason} -> + {400, #{code => <<"CHANGE_PWD_FAIL">>, message => Reason}} + end. row(#mqtt_admin{username = Username, tags = Tags}) -> #{username => Username, tags => Tags}. -return(_) -> -%% TODO: V5 API - ok. +bad_request() -> + response_schema(<<"Bad Request">>, + #{ + type => object, + properties => #{ + message => #{type => string}, + code => #{type => string} + } + }).