-module(handler_booking_by_id). -include("records.hrl"). -export([init/2]). init(Req, Opts) -> handle(Req, Opts). handle(Req, _Opts) -> case cowboy_req:method(Req) of <<"GET">> -> get_booking(Req); <<"PUT">> -> update_booking(Req); <<"DELETE">> -> cancel_booking(Req); _ -> send_error(Req, 405, <<"Method not allowed">>) end. %% GET /v1/bookings/:id - получение бронирования get_booking(Req) -> case handler_auth:authenticate(Req) of {ok, UserId, Req1} -> BookingId = cowboy_req:binding(id, Req1), case logic_booking:get_booking(UserId, BookingId) of {ok, Booking} -> Response = booking_to_json(Booking), send_json(Req1, 200, Response); {error, access_denied} -> send_error(Req1, 403, <<"Access denied">>); {error, not_found} -> send_error(Req1, 404, <<"Booking not found">>); {error, _} -> send_error(Req1, 500, <<"Internal server error">>) end; {error, Code, Message, Req1} -> send_error(Req1, Code, Message) end. %% PUT /v1/bookings/:id - подтверждение/отклонение бронирования (владельцем) update_booking(Req) -> case handler_auth:authenticate(Req) of {ok, UserId, Req1} -> BookingId = 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) -> case maps:get(<<"action">>, Decoded, undefined) of <<"confirm">> -> case logic_booking:confirm_booking(UserId, BookingId, confirm) of {ok, Booking} -> Response = booking_to_json(Booking), send_json(Req2, 200, Response); {error, access_denied} -> send_error(Req2, 403, <<"Access denied">>); {error, not_found} -> send_error(Req2, 404, <<"Booking not found">>); {error, _} -> send_error(Req2, 500, <<"Internal server error">>) end; <<"decline">> -> case logic_booking:confirm_booking(UserId, BookingId, decline) of {ok, Booking} -> Response = booking_to_json(Booking), send_json(Req2, 200, Response); {error, access_denied} -> send_error(Req2, 403, <<"Access denied">>); {error, not_found} -> send_error(Req2, 404, <<"Booking not found">>); {error, _} -> send_error(Req2, 500, <<"Internal server error">>) end; _ -> send_error(Req2, 400, <<"Missing or invalid 'action' field. Use 'confirm' or 'decline'">>) end; _ -> send_error(Req2, 400, <<"Invalid JSON">>) catch _:_ -> send_error(Req2, 400, <<"Invalid JSON format">>) end; {error, Code, Message, Req1} -> send_error(Req1, Code, Message) end. %% DELETE /v1/bookings/:id - отмена бронирования (участником) cancel_booking(Req) -> case handler_auth:authenticate(Req) of {ok, UserId, Req1} -> BookingId = cowboy_req:binding(id, Req1), case logic_booking:cancel_booking(UserId, BookingId) of {ok, Booking} -> Response = booking_to_json(Booking), send_json(Req1, 200, Response); {error, access_denied} -> send_error(Req1, 403, <<"Access denied">>); {error, not_found} -> send_error(Req1, 404, <<"Booking not found">>); {error, _} -> send_error(Req1, 500, <<"Internal server error">>) end; {error, Code, Message, Req1} -> send_error(Req1, Code, Message) end. %% Вспомогательные функции booking_to_json(Booking) -> #{ id => Booking#booking.id, event_id => Booking#booking.event_id, user_id => Booking#booking.user_id, status => Booking#booking.status, confirmed_at => case Booking#booking.confirmed_at of undefined -> null; Dt -> datetime_to_iso8601(Dt) end, created_at => datetime_to_iso8601(Booking#booking.created_at), updated_at => datetime_to_iso8601(Booking#booking.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])). 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, []}.