Files
EventHubBack/src/logic/logic_calendar_share.erl
T
aleksey 331000a464
CI / test (push) Failing after 6m37s
CI / deploy-ift (push) Has been skipped
CI / e2e-ift (push) Has been skipped
CI / deploy-stage (push) Has been skipped
CI / e2e-stage (push) Has been skipped
feat(share): calendar_share invite/ACL for personal and commercial.
Co-editor and deputy grants with mirror_to_default; personal out of search; list owned+shared. Refs EventHub/EventHubBack#73
2026-08-15 23:20:11 +03:00

120 lines
4.0 KiB
Erlang

%%%-------------------------------------------------------------------
%%% @doc Grants calendar_share: list / revoke / rights / mirror.
%%% @end
%%%-------------------------------------------------------------------
-module(logic_calendar_share).
-include("records.hrl").
-export([
list/2,
revoke/3,
update_rights/4,
update_my_mirror/3,
get_rights/2,
can_manage_shares/2,
to_json/1
]).
-spec list(ActorId :: binary(), CalendarId :: binary()) ->
{ok, [#calendar_share{}]} | {error, not_found | access_denied}.
list(ActorId, CalendarId) ->
case require_can_view_shares(ActorId, CalendarId) of
{ok, _} -> {ok, core_calendar_share:list_by_calendar(CalendarId)};
Error -> Error
end.
-spec revoke(ActorId :: binary(), CalendarId :: binary(), TargetUserId :: binary()) ->
ok | {error, not_found | access_denied | term()}.
revoke(ActorId, CalendarId, TargetUserId) ->
case require_can_manage(ActorId, CalendarId) of
{ok, _} ->
case core_calendar_share:delete(CalendarId, TargetUserId) of
ok -> ok;
{error, _} = E -> E
end;
Error -> Error
end.
-spec update_rights(ActorId :: binary(), CalendarId :: binary(),
TargetUserId :: binary(), Rights :: read | write | admin) ->
{ok, #calendar_share{}} | {error, not_found | access_denied | bad_request | term()}.
update_rights(ActorId, CalendarId, TargetUserId, Rights) ->
case valid_rights(Rights) of
false -> {error, bad_request};
true ->
case require_can_manage(ActorId, CalendarId) of
{ok, _} -> core_calendar_share:update_rights(CalendarId, TargetUserId, Rights);
Error -> Error
end
end.
%% Invitee updates own mirror preference (personal shares only meaningful).
-spec update_my_mirror(UserId :: binary(), CalendarId :: binary(), Mirror :: boolean()) ->
{ok, #calendar_share{}} | {error, not_found | access_denied | term()}.
update_my_mirror(UserId, CalendarId, Mirror) when is_boolean(Mirror) ->
case core_calendar_share:get(CalendarId, UserId) of
{ok, _} -> core_calendar_share:update_mirror(CalendarId, UserId, Mirror);
{error, not_found} -> {error, not_found}
end;
update_my_mirror(_, _, _) ->
{error, bad_request}.
-spec get_rights(UserId :: binary(), CalendarId :: binary()) ->
none | read | write | admin.
get_rights(UserId, CalendarId) ->
case core_calendar_share:get(CalendarId, UserId) of
{ok, #calendar_share{rights = R}} -> R;
{error, not_found} -> none
end.
-spec can_manage_shares(UserId :: binary(), #calendar{}) -> boolean().
can_manage_shares(UserId, #calendar{owner_id = UserId, status = active}) ->
true;
can_manage_shares(UserId, #calendar{id = CalId, status = active}) ->
get_rights(UserId, CalId) =:= admin;
can_manage_shares(_, _) ->
false.
-spec to_json(#calendar_share{}) -> map().
to_json(S) ->
#{
id => S#calendar_share.id,
calendar_id => S#calendar_share.calendar_id,
user_id => S#calendar_share.user_id,
rights => S#calendar_share.rights,
mirror_to_default => S#calendar_share.mirror_to_default
}.
%%%===================================================================
%%% Internal
%%%===================================================================
require_can_view_shares(ActorId, CalendarId) ->
case core_calendar:get_by_id(CalendarId) of
{ok, #calendar{status = active} = Cal} ->
case can_manage_shares(ActorId, Cal)
orelse Cal#calendar.owner_id =:= ActorId
orelse get_rights(ActorId, CalendarId) =/= none of
true -> {ok, Cal};
false -> {error, access_denied}
end;
{ok, _} -> {error, not_found};
Error -> Error
end.
require_can_manage(ActorId, CalendarId) ->
case core_calendar:get_by_id(CalendarId) of
{ok, #calendar{status = active} = Cal} ->
case can_manage_shares(ActorId, Cal) of
true -> {ok, Cal};
false -> {error, access_denied}
end;
{ok, _} -> {error, not_found};
Error -> Error
end.
valid_rights(read) -> true;
valid_rights(write) -> true;
valid_rights(admin) -> true;
valid_rights(_) -> false.