-module(admin_handler_user_by_id). -include("records.hrl"). -export([init/2]). -export([user_to_json/1, convert_updates/1]). init(Req, Opts) -> handle(Req, Opts). handle(Req, _Opts) -> case cowboy_req:method(Req) of <<"GET">> -> get_user(Req); <<"PUT">> -> update_user(Req); <<"DELETE">> -> delete_user(Req); _ -> send_error(Req, 405, <<"Method not allowed">>) end. get_user(Req) -> case handler_auth:authenticate(Req) of {ok, AdminId, Req1} -> case is_admin(AdminId) of true -> UserId = cowboy_req:binding(id, Req1), case core_user:get_by_id(UserId) of {ok, User} when User#user.status =:= deleted -> send_error(Req1, 404, <<"User not found">>); {ok, User} -> send_json(Req1, 200, user_to_json(User)); {error, not_found} -> send_error(Req1, 404, <<"User not found">>) end; false -> send_error(Req1, 403, <<"Admin access required">>) end; {error, Code, Message, Req1} -> send_error(Req1, Code, Message) end. update_user(Req) -> case handler_auth:authenticate(Req) of {ok, AdminId, Req1} -> case is_admin(AdminId) of true -> UserId = cowboy_req:binding(id, Req1), {ok, Body, Req2} = cowboy_req:read_body(Req1), try jsx:decode(Body, [return_maps]) of Decoded when is_map(Decoded) -> Updates = maps:to_list(Decoded), Converted = convert_updates(Updates), case core_user:update(UserId, Converted) of {ok, User} -> send_json(Req2, 200, user_to_json(User)); {error, not_found} -> send_error(Req2, 404, <<"User not found">>); {error, _} -> send_error(Req2, 500, <<"Internal server error">>) end; _ -> send_error(Req2, 400, <<"Invalid JSON">>) catch _:_ -> send_error(Req2, 400, <<"Invalid JSON format">>) end; false -> send_error(Req1, 403, <<"Admin access required">>) end; {error, Code, Message, Req1} -> send_error(Req1, Code, Message) end. delete_user(Req) -> case handler_auth:authenticate(Req) of {ok, AdminId, Req1} -> case is_admin(AdminId) of true -> UserId = cowboy_req:binding(id, Req1), case core_user:delete(UserId) of {ok, _} -> send_json(Req1, 200, #{status => <<"deleted">>}); {error, not_found} -> send_error(Req1, 404, <<"User not found">>) end; false -> send_error(Req1, 403, <<"Admin access required">>) end; {error, Code, Message, Req1} -> send_error(Req1, Code, Message) end. is_admin(UserId) -> case core_user:get_by_id(UserId) of {ok, User} -> User#user.role =:= admin; _ -> false end. user_to_json(User) -> #{ id => User#user.id, email => User#user.email, role => User#user.role, status => User#user.status, created_at => datetime_to_iso8601(User#user.created_at), updated_at => datetime_to_iso8601(User#user.updated_at) }. datetime_to_iso8601({{Year, Month, Day}, {Hour, Minute, Second}}) -> iolist_to_binary(io_lib:format("~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0BZ", [Year, Month, Day, Hour, Minute, Second])). convert_updates(Updates) -> lists:map(fun ({<<"status">>, Value}) -> {status, binary_to_existing_atom(Value)}; ({<<"role">>, Value}) -> {role, binary_to_existing_atom(Value)}; (Other) -> Other end, Updates). send_json(Req, Status, Data) -> Body = jsx:encode(Data), cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req), {ok, Body, []}. send_error(Req, Status, Message) -> Body = jsx:encode(#{error => Message}), cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req), {ok, Body, []}.