feat: GET /v1/user/booking-requests + search image_url. Fixes EventHub/EventHubBack#59
CI / test (push) Successful in 7m1s
CI / deploy-ift (push) Successful in 5m59s
CI / e2e-ift (push) Successful in 1m34s
CI / deploy-stage (push) Successful in 2m47s
CI / e2e-stage (push) Successful in 1m18s

This commit is contained in:
2026-07-27 14:53:25 +03:00
parent b25c0447cd
commit 1d9752bb69
8 changed files with 263 additions and 8 deletions
@@ -0,0 +1,112 @@
%%%-------------------------------------------------------------------
%%% @doc Pending booking requests for the current user (owner / specialist inbox).
%%% GET /v1/user/booking-requests
%%% @end
%%%-------------------------------------------------------------------
-module(handler_user_booking_requests).
-behaviour(cowboy_handler).
-export([init/2]).
-export([trails/0]).
-include("records.hrl").
-spec init(cowboy_req:req(), any()) -> {ok, cowboy_req:req(), any()}.
init(Req, Opts) ->
handle(Req, Opts).
-spec trails() -> [map()].
trails() ->
[
#{
path => <<"/v1/user/booking-requests">>,
method => <<"GET">>,
description => <<"List pending booking requests the user can confirm/decline">>,
tags => [<<"Bookings">>],
responses => #{
200 => #{
description => <<"Array of enriched booking requests">>,
content => #{<<"application/json">> => #{schema => #{
type => array,
items => request_schema()
}}}
},
401 => #{description => <<"Unauthorized">>}
}
}
].
request_schema() ->
#{
type => object,
properties => #{
id => #{type => string},
event_id => #{type => string},
user_id => #{type => string},
status => #{type => string, enum => [<<"pending">>]},
role => #{type => string, enum => [<<"owner">>, <<"specialist">>]},
user_nickname => #{type => string, nullable => true},
user_email => #{type => string, nullable => true},
created_at => #{type => string, format => <<"date-time">>},
event => #{
type => object,
properties => #{
id => #{type => string},
calendar_id => #{type => string},
calendar_title => #{type => string, nullable => true},
title => #{type => string},
start_time => #{type => string, format => <<"date-time">>},
duration => #{type => integer},
specialist_id => #{type => string, nullable => true}
}
}
}
}.
-spec handle(cowboy_req:req(), any()) -> {ok, cowboy_req:req(), any()}.
handle(Req, _Opts) ->
case cowboy_req:method(Req) of
<<"GET">> -> list_requests(Req);
_ -> handler_utils:send_error(Req, 405, <<"Method not allowed">>)
end.
-spec list_requests(cowboy_req:req()) -> {ok, cowboy_req:req(), any()}.
list_requests(Req) ->
case handler_utils:auth_user(Req) of
{ok, UserId, Req1} ->
case logic_booking:list_user_booking_requests(UserId) of
{ok, Items} ->
Response = [request_to_json(I) || I <- Items],
handler_utils:send_json(Req1, 200, Response);
{error, _} ->
handler_utils:send_error(Req1, 500, <<"Internal server error">>)
end;
{error, Code, Message, Req1} ->
handler_utils:send_error(Req1, Code, Message)
end.
-spec request_to_json({#booking{}, #event{}, owner | specialist}) -> map().
request_to_json({Booking, Event, Role}) ->
CalendarTitle = case core_calendar:get_by_id(Event#event.calendar_id) of
{ok, Cal} -> Cal#calendar.title;
_ -> null
end,
SpecialistId = case Event#event.specialist_id of
<<>> -> null;
undefined -> null;
Sid -> Sid
end,
Base = handler_utils:booking_to_json(Booking),
EventMap = #{
id => Event#event.id,
calendar_id => Event#event.calendar_id,
calendar_title => CalendarTitle,
title => Event#event.title,
start_time => handler_utils:datetime_to_iso8601(Event#event.start_time),
duration => Event#event.duration,
specialist_id => SpecialistId
},
Base#{
role => Role,
event => EventMap
}.