%%%------------------------------------------------------------------- %%% @doc Invitee: входящие invites + accept/decline. %%% %%% GET /v1/user/specialist-invites %%% POST /v1/specialist-invites/:id/accept %%% POST /v1/specialist-invites/:id/decline %%% POST /v1/specialist-invites/accept body: {token} %%% @end %%%------------------------------------------------------------------- -module(handler_specialist_invites). -behaviour(cowboy_handler). -export([init/2, trails/0]). -include("records.hrl"). init(Req, Opts) -> handle(Req, Opts). trails() -> IdParam = #{name => <<"id">>, in => <<"path">>, required => true, schema => #{type => string}}, [ #{path => <<"/v1/user/specialist-invites">>, method => <<"GET">>, description => <<"Incoming specialist invites">>, tags => [<<"Users">>], responses => #{200 => #{description => <<"OK">>}}}, #{path => <<"/v1/specialist-invites/accept">>, method => <<"POST">>, description => <<"Accept invite by email token">>, tags => [<<"Users">>], responses => #{200 => #{description => <<"OK">>}}}, #{path => <<"/v1/specialist-invites/:id/accept">>, method => <<"POST">>, description => <<"Accept specialist invite">>, tags => [<<"Users">>], parameters => [IdParam], responses => #{200 => #{description => <<"OK">>}}}, #{path => <<"/v1/specialist-invites/:id/decline">>, method => <<"POST">>, description => <<"Decline specialist invite">>, tags => [<<"Users">>], parameters => [IdParam], responses => #{200 => #{description => <<"OK">>}}} ]. handle(Req, _Opts) -> Method = cowboy_req:method(Req), Path = cowboy_req:path(Req), case Method of <<"GET">> -> list_incoming(Req); <<"POST">> -> case Path of <<"/v1/specialist-invites/accept">> -> accept_token(Req); _ -> case {cowboy_req:binding(id, Req), path_action(Path)} of {Id, accept} when is_binary(Id) -> accept_id(Req, Id); {Id, decline} when is_binary(Id) -> decline_id(Req, Id); _ -> handler_utils:send_error(Req, 404, <<"Not found">>) end end; _ -> handler_utils:send_error(Req, 405, <<"Method not allowed">>) end. path_action(Path) -> case binary:match(Path, <<"/accept">>) of nomatch -> case binary:match(Path, <<"/decline">>) of nomatch -> unknown; _ -> decline end; _ -> accept end. list_incoming(Req) -> case handler_utils:auth_user(Req) of {ok, UserId, Req1} -> {ok, List} = logic_specialist_invite:list_incoming(UserId), handler_utils:send_json(Req1, 200, [logic_specialist_invite:to_json(I) || I <- List]); {error, Code, Message, Req1} -> handler_utils:send_error(Req1, Code, Message) end. accept_id(Req, InviteId) -> case handler_utils:auth_user(Req) of {ok, UserId, Req1} -> reply_accept(Req1, logic_specialist_invite:accept(UserId, InviteId)); {error, Code, Message, Req1} -> handler_utils:send_error(Req1, Code, Message) end. decline_id(Req, InviteId) -> case handler_utils:auth_user(Req) of {ok, UserId, Req1} -> case logic_specialist_invite:decline(UserId, InviteId) of {ok, Inv} -> handler_utils:send_json(Req1, 200, logic_specialist_invite:to_json(Inv)); {error, Reason} -> map_decide_error(Req1, Reason) end; {error, Code, Message, Req1} -> handler_utils:send_error(Req1, Code, Message) end. accept_token(Req) -> case handler_utils:auth_user(Req) of {ok, UserId, Req1} -> {ok, Body, Req2} = cowboy_req:read_body(Req1), try jsx:decode(Body, [return_maps]) of #{<<"token">> := Token} when is_binary(Token), Token =/= <<>> -> reply_accept(Req2, logic_specialist_invite:accept_by_token(UserId, Token)); _ -> handler_utils:send_error(Req2, 400, <<"token required">>) catch _:_ -> handler_utils:send_error(Req2, 400, <<"Invalid JSON">>) end; {error, Code, Message, Req1} -> handler_utils:send_error(Req1, Code, Message) end. reply_accept(Req, {ok, Inv, Spec}) -> handler_utils:send_json(Req, 200, #{ invite => logic_specialist_invite:to_json(Inv), specialist => logic_calendar_specialist:to_json(Spec) }); reply_accept(Req, {error, Reason}) -> map_decide_error(Req, Reason). map_decide_error(Req, not_found) -> handler_utils:send_error(Req, 404, <<"Not found">>); map_decide_error(Req, access_denied) -> handler_utils:send_error(Req, 403, <<"Access denied">>); map_decide_error(Req, not_pending) -> handler_utils:send_error(Req, 409, <<"Invite is not pending">>); map_decide_error(Req, expired) -> handler_utils:send_error(Req, 410, <<"Invite expired">>); map_decide_error(Req, _) -> handler_utils:send_error(Req, 500, <<"Internal server error">>).