Files
EventHubBack/src/logic/logic_calendar.erl
T

165 lines
5.9 KiB
Erlang

-module(logic_calendar).
-include("records.hrl").
-export([create_calendar/3, create_calendar/4, get_calendar/2, list_calendars/1,
update_calendar/3, delete_calendar/2]).
-export([can_access/2, can_edit/2]).
-export([admin_list_all/0, admin_get_by_id/1, admin_update/2, admin_delete/1]).
%% Создание календаря с политикой по умолчанию (manual)
create_calendar(UserId, Title, Description) ->
create_calendar(UserId, Title, Description, manual).
%% Создание календаря с указанной политикой подтверждения
create_calendar(UserId, Title, Description, Confirmation) ->
Type = personal, % По умолчанию
create_calendar(UserId, Title, Description, Confirmation, Type).
create_calendar(UserId, Title, Description, Confirmation, Type) ->
case core_user:get_by_id(UserId) of
{ok, User} ->
case User#user.status of
active ->
case Type of
commercial ->
case logic_subscription:can_create_commercial_calendar(UserId) of
true ->
core_calendar:create(UserId, Title, Description, Confirmation, Type);
false ->
{error, subscription_required}
end;
personal ->
core_calendar:create(UserId, Title, Description, Confirmation, Type)
end;
_ ->
{error, user_inactive}
end;
{error, _} ->
{error, user_not_found}
end.
%% Получение календаря с проверкой доступа
get_calendar(UserId, CalendarId) ->
case core_calendar:get_by_id(CalendarId) of
{ok, Calendar} ->
case can_access(UserId, Calendar) of
true -> {ok, Calendar};
false -> {error, access_denied}
end;
Error ->
Error
end.
%% Список календарей пользователя
list_calendars(UserId) ->
core_calendar:list_by_owner(UserId).
%% Обновление календаря
update_calendar(UserId, CalendarId, Updates) ->
case core_calendar:get_by_id(CalendarId) of
{ok, Calendar} ->
case can_edit(UserId, Calendar) of
true ->
ValidUpdates = validate_updates(Updates),
core_calendar:update(CalendarId, ValidUpdates);
false ->
{error, access_denied}
end;
Error ->
Error
end.
%% Удаление календаря
delete_calendar(UserId, CalendarId) ->
case core_calendar:get_by_id(CalendarId) of
{ok, Calendar} ->
case can_edit(UserId, Calendar) of
true ->
core_calendar:delete(CalendarId);
false ->
{error, access_denied}
end;
Error ->
Error
end.
%% Проверка прав доступа (просмотр)
can_access(UserId, #calendar{owner_id = UserId, status = active}) ->
true;
can_access(_UserId, #calendar{type = commercial, status = active}) ->
true;
can_access(_UserId, _) ->
false.
%% Проверка прав редактирования
can_edit(UserId, #calendar{owner_id = UserId, status = active}) ->
true;
can_edit(_UserId, #calendar{owner_id = _OwnerId}) ->
false;
can_edit(_, _) ->
false.
%% Валидация полей обновления
validate_updates(Updates) ->
lists:filter(fun validate_update/1, Updates).
validate_update({title, Value}) when is_binary(Value) -> true;
validate_update({description, Value}) when is_binary(Value) -> true;
validate_update({tags, Value}) when is_list(Value) -> true;
validate_update({type, Value}) when Value =:= personal; Value =:= commercial -> true;
validate_update({confirmation, Value}) ->
case Value of
auto -> true;
manual -> true;
{timeout, N} when is_integer(N), N > 0 -> true;
_ -> false
end;
validate_update(_) -> false.
%% ─── Административные функции ────────────────────────────────────────
-spec admin_list_all() -> {ok, [map()]} | {error, term()}.
admin_list_all() ->
Calendars = core_calendar:list_all(),
{ok, Calendars}.
-spec admin_get_by_id(binary()) -> {ok, #calendar{}} | {error, not_found}.
admin_get_by_id(CalendarId) ->
core_calendar:get_by_id(CalendarId).
-spec admin_update(binary(), map()) -> {ok, #calendar{}} | {error, term()}.
admin_update(CalendarId, Updates) when is_map(Updates) ->
%% Преобразуем map в список {атом, значение}, исключая служебные ключи
TupleList = maps:fold(fun key_to_update/3, [], Updates),
core_calendar:update(CalendarId, TupleList).
-spec admin_delete(binary()) -> ok | {error, term()}.
admin_delete(Id) ->
case core_calendar:delete(Id) of
{ok, _} -> ok;
Error -> Error
end.
key_to_update(<<"title">>, V, Acc) -> [{title, V} | Acc];
key_to_update(<<"description">>, V, Acc) -> [{description, V} | Acc];
key_to_update(<<"short_name">>, V, Acc) -> [{short_name, V} | Acc];
key_to_update(<<"category">>, V, Acc) -> [{category, V} | Acc];
key_to_update(<<"color">>, V, Acc) -> [{color, V} | Acc];
key_to_update(<<"image_url">>, V, Acc) -> [{image_url, V} | Acc];
key_to_update(<<"settings">>, V, Acc) -> [{settings, V} | Acc];
key_to_update(<<"tags">>, V, Acc) -> [{tags, V} | Acc];
key_to_update(<<"type">>, V, Acc) ->
Type = binary_to_existing_atom(V, utf8),
[{type, Type} | Acc];
key_to_update(<<"status">>, V, Acc) ->
Status = binary_to_existing_atom(V, utf8),
[{status, Status} | Acc];
key_to_update(<<"confirmation">>, V, Acc) ->
% confirmation может быть строкой "auto", "manual" или "timeout:N"
Conf = case V of
<<"auto">> -> auto;
<<"manual">> -> manual;
_ -> V % для сложных значений пока оставляем как есть
end,
[{confirmation, Conf} | Acc];
key_to_update(<<"reason">>, V, Acc) -> [{reason, V} | Acc];
key_to_update(_, _V, Acc) -> Acc.