fix: require calendar owner or admin for booking confirm/decline. Fixes EventHub/EventHubBack#53
CI / test (push) Successful in 6m49s
CI / deploy-ift (push) Successful in 2m28s
CI / e2e-ift (push) Successful in 1m26s
CI / deploy-stage (push) Successful in 1m57s
CI / e2e-stage (push) Successful in 1m49s

This commit is contained in:
2026-07-22 10:53:01 +03:00
parent 9886dff8bf
commit fdb08eb453
4 changed files with 123 additions and 26 deletions
+1
View File
@@ -64,6 +64,7 @@ trails() ->
responses => #{
200 => #{description => <<"Booking updated">>},
400 => #{description => <<"Invalid action">>},
403 => #{description => <<"Access denied">>},
404 => #{description => <<"Booking not found">>}
}
},
Regular → Executable
+61 -24
View File
@@ -32,31 +32,54 @@ create_booking(UserId, EventId) ->
%%%-------------------------------------------------------------------
%%% @doc Подтверждение бронирования (двухарная версия).
%%% Только владелец календаря события или admin.
%%% @end
%%%-------------------------------------------------------------------
-spec confirm_booking(BookingId :: binary(), UserId :: binary()) ->
{ok, #booking{}} | {error, not_found | access_denied}.
confirm_booking(BookingId, _UserId) ->
confirm_booking(BookingId, UserId) ->
case core_booking:get_by_id(BookingId) of
{ok, Booking} ->
case Booking#booking.status of
pending ->
Now = calendar:universal_time(),
core_booking:update(BookingId, [{status, confirmed}, {confirmed_at, Now}]);
_ ->
{error, access_denied}
case can_manage_event_bookings(UserId, Booking#booking.event_id) of
true ->
case Booking#booking.status of
pending ->
Now = calendar:universal_time(),
core_booking:update(BookingId, [{status, confirmed}, {confirmed_at, Now}]);
_ ->
{error, access_denied}
end;
{error, Reason} ->
{error, Reason}
end;
Error -> Error
end.
%%%-------------------------------------------------------------------
%%% @doc Подтверждение бронирования (трёхарная версия для обработчиков).
%%% @doc Подтверждение или отклонение бронирования (для обработчиков).
%%% `decline` переводит pending-заявку в `cancelled`.
%%% @end
%%%-------------------------------------------------------------------
-spec confirm_booking(UserId :: binary(), BookingId :: binary(), confirm) ->
-spec confirm_booking(UserId :: binary(), BookingId :: binary(), confirm | decline) ->
{ok, #booking{}} | {error, not_found | access_denied}.
confirm_booking(UserId, BookingId, confirm) ->
confirm_booking(BookingId, UserId).
confirm_booking(BookingId, UserId);
confirm_booking(UserId, BookingId, decline) ->
case core_booking:get_by_id(BookingId) of
{ok, Booking} ->
case can_manage_event_bookings(UserId, Booking#booking.event_id) of
true ->
case Booking#booking.status of
pending ->
core_booking:update(BookingId, [{status, cancelled}]);
_ ->
{error, access_denied}
end;
{error, Reason} ->
{error, Reason}
end;
Error -> Error
end.
%%%-------------------------------------------------------------------
%%% @doc Отмена бронирования (двухарная версия).
@@ -167,20 +190,11 @@ list_event_bookings(EventId) ->
-spec list_event_bookings(UserId :: binary(), EventId :: binary()) ->
{ok, [#booking{}]} | {error, not_found | access_denied}.
list_event_bookings(UserId, EventId) ->
case core_event:get_by_id(EventId) of
{ok, Event} ->
case core_calendar:get_by_id(Event#event.calendar_id) of
{ok, Calendar} ->
case admin_utils:is_admin(UserId)
orelse Calendar#calendar.owner_id =:= UserId of
true -> core_booking:list_by_event(EventId);
false -> {error, access_denied}
end;
{error, not_found} ->
{error, not_found}
end;
{error, not_found} ->
{error, not_found}
case can_manage_event_bookings(UserId, EventId) of
true ->
core_booking:list_by_event(EventId);
{error, Reason} ->
{error, Reason}
end.
%%%-------------------------------------------------------------------
@@ -195,6 +209,29 @@ list_bookings_admin() ->
%%% ВНУТРЕННИЕ ФУНКЦИИ
%%%===================================================================
%%%-------------------------------------------------------------------
%%% @doc Владелец календаря события или admin может управлять заявками.
%%% @end
%%%-------------------------------------------------------------------
-spec can_manage_event_bookings(UserId :: binary(), EventId :: binary()) ->
true | {error, not_found | access_denied}.
can_manage_event_bookings(UserId, EventId) ->
case core_event:get_by_id(EventId) of
{ok, Event} ->
case core_calendar:get_by_id(Event#event.calendar_id) of
{ok, Calendar} ->
case Calendar#calendar.owner_id =:= UserId
orelse admin_utils:is_admin(UserId) of
true -> true;
false -> {error, access_denied}
end;
{error, not_found} ->
{error, not_found}
end;
{error, not_found} ->
{error, not_found}
end.
%%%-------------------------------------------------------------------
%%% @doc Проверка вместимости события.
%%% `undefined` и `0` означают неограниченную вместимость.