Files
EventHubBack/src/handlers/admin/admin_handler_me.erl
T

146 lines
5.2 KiB
Erlang

%%%-------------------------------------------------------------------
%%% @doc Административный обработчик профиля текущего администратора.
%%% GET – получить свой профиль.
%%% PUT – обновить свой профиль.
%%% @end
%%%-------------------------------------------------------------------
-module(admin_handler_me).
-behaviour(cowboy_handler).
-export([init/2]).
-export([trails/0]).
-include("records.hrl").
%%% cowboy_handler callback
-spec init(cowboy_req:req(), any()) -> {ok, cowboy_req:req(), any()}.
init(Req, _Opts) ->
case cowboy_req:method(Req) of
<<"GET">> -> get_me(Req);
<<"PUT">> -> update_me(Req);
_ -> handler_utils:send_error(Req, 405, <<"Method not allowed">>)
end.
%%% Swagger metadata
-spec trails() -> [map()].
trails() ->
[
#{ % GET
path => <<"/v1/admin/me">>,
method => <<"GET">>,
description => <<"Get current admin profile">>,
tags => [<<"Admins">>],
responses => #{
200 => #{
description => <<"Admin profile">>,
content => #{<<"application/json">> => #{schema => admin_schema()}}
}
}
},
#{ % PUT
path => <<"/v1/admin/me">>,
method => <<"PUT">>,
description => <<"Update current admin profile">>,
tags => [<<"Admins">>],
requestBody => #{
required => true,
content => #{<<"application/json">> => #{schema => admin_update_schema()}}
},
responses => #{
200 => #{description => <<"Updated profile">>}
}
}
].
-spec admin_schema() -> map().
admin_schema() ->
#{
type => object,
properties => #{
id => #{type => string},
email => #{type => string},
role => #{type => string},
status => #{type => string},
nickname => #{type => string, nullable => true},
avatar_url => #{type => string, nullable => true},
timezone => #{type => string, nullable => true},
language => #{type => string, nullable => true},
phone => #{type => string, nullable => true},
preferences => #{type => object, nullable => true},
last_login => #{type => string, format => <<"date-time">>},
created_at => #{type => string, format => <<"date-time">>},
updated_at => #{type => string, format => <<"date-time">>}
}
}.
-spec admin_update_schema() -> map().
admin_update_schema() ->
#{
type => object,
properties => #{
nickname => #{type => string},
avatar_url => #{type => string},
timezone => #{type => string},
language => #{type => string},
phone => #{type => string},
preferences => #{type => object}
}
}.
%%% Internal functions
-spec get_me(cowboy_req:req()) -> {ok, binary(), cowboy_req:req()}.
get_me(Req) ->
case handler_utils:auth_admin(Req) of
{ok, AdminId, Req1} ->
case logic_admin:get_admin(AdminId) of
{ok, Admin} ->
handler_utils:send_json(Req1, 200, handler_utils:admin_to_json(Admin));
{error, not_found} ->
handler_utils:send_error(Req1, 404, <<"Admin not found">>);
{error, _} ->
handler_utils:send_error(Req1, 500, <<"Internal server error">>)
end;
{error, Code, Msg, Req1} ->
handler_utils:send_error(Req1, Code, Msg)
end.
-spec update_me(cowboy_req:req()) -> {ok, binary(), cowboy_req:req()}.
update_me(Req) ->
case handler_utils:auth_admin(Req) of
{ok, AdminId, Req1} ->
{ok, Body, Req2} = cowboy_req:read_body(Req1),
try jsx:decode(Body, [return_maps]) of
UpdatesMap when is_map(UpdatesMap) ->
Updates0 = maps:to_list(UpdatesMap),
Updates = convert_admin_fields(Updates0),
case logic_admin:update_admin(AdminId, Updates) of
{ok, Admin} ->
% Аудит обновления профиля
admin_utils:log_admin_action(AdminId, <<"update_me">>, <<"admin">>, AdminId, Req2),
handler_utils:send_json(Req2, 200, handler_utils:admin_to_json(Admin));
{error, not_found} ->
handler_utils:send_error(Req2, 404, <<"Admin not found">>);
{error, _} ->
handler_utils:send_error(Req2, 500, <<"Internal server error">>)
end;
_ ->
handler_utils:send_error(Req2, 400, <<"Invalid JSON">>)
catch
_:_ -> handler_utils:send_error(Req1, 400, <<"Invalid JSON format">>)
end;
{error, Code, Msg, Req1} ->
handler_utils:send_error(Req1, Code, Msg)
end.
%% @private Преобразует бинарные ключи в атомы для обновлений администратора.
-spec convert_admin_fields([{binary(), term()}]) -> [{atom(), term()}].
convert_admin_fields(Updates) ->
lists:map(fun
({<<"nickname">>, V}) -> {nickname, V};
({<<"avatar_url">>, V}) -> {avatar_url, V};
({<<"timezone">>, V}) -> {timezone, V};
({<<"language">>, V}) -> {language, V};
({<<"phone">>, V}) -> {phone, V};
({<<"preferences">>, V}) -> {preferences, V};
(Other) -> Other
end, Updates).