%%%------------------------------------------------------------------- %%% @doc Логика специалистов commercial-календаря. %%% @end %%%------------------------------------------------------------------- -module(logic_calendar_specialist). -include("records.hrl"). -export([list/2, add/5, update/4, remove/3, to_json/1, ensure_owner_specialist/1]). -spec list(ActorId :: binary(), CalendarId :: binary()) -> {ok, [#calendar_specialist{}]} | {error, not_found | access_denied}. list(ActorId, CalendarId) -> case logic_calendar:get_calendar(ActorId, CalendarId) of {ok, Cal} -> {ok, core_calendar_specialist:list_by_calendar(Cal#calendar.id)}; Error -> Error end. -spec add(OwnerId :: binary(), CalendarId :: binary(), UserId :: binary(), Name :: binary(), Specs :: [binary()]) -> {ok, #calendar_specialist{}} | {error, not_found | access_denied | not_commercial | user_not_found | already_exists | term()}. add(OwnerId, CalendarId, UserId, Name, Specs) -> case require_owner_commercial(OwnerId, CalendarId) of {ok, _} -> case core_user:get_by_id(UserId) of {ok, _} -> core_calendar_specialist:create(CalendarId, UserId, Name, Specs); {error, _} -> {error, user_not_found} end; Error -> Error end. -spec update(OwnerId :: binary(), CalendarId :: binary(), UserId :: binary(), Updates :: [{atom(), term()}]) -> {ok, #calendar_specialist{}} | {error, not_found | access_denied | not_commercial | term()}. update(OwnerId, CalendarId, UserId, Updates) -> case require_owner_commercial(OwnerId, CalendarId) of {ok, _} -> core_calendar_specialist:update(CalendarId, UserId, Updates); Error -> Error end. -spec remove(OwnerId :: binary(), CalendarId :: binary(), UserId :: binary()) -> ok | {error, not_found | access_denied | not_commercial | owner_specialist_protected | term()}. remove(OwnerId, CalendarId, UserId) -> case require_owner_commercial(OwnerId, CalendarId) of {ok, #calendar{owner_id = CalOwnerId}} when UserId =:= CalOwnerId -> {error, owner_specialist_protected}; {ok, _} -> core_calendar_specialist:delete(CalendarId, UserId); Error -> Error end. %% @doc Idempotent: commercial calendar always has a specialist row for owner. %% Default status=active; name from nickname (else email). No-op if already present. -spec ensure_owner_specialist(#calendar{}) -> ok | {error, term()}. ensure_owner_specialist(#calendar{id = CalId, owner_id = OwnerId, type = commercial}) -> case core_calendar_specialist:get_by_calendar_and_user(CalId, OwnerId) of {ok, _} -> ok; {error, not_found} -> case core_calendar_specialist:create(CalId, OwnerId, owner_display_name(OwnerId), []) of {ok, _} -> ok; {error, already_exists} -> ok; {error, _} = Err -> Err end end; ensure_owner_specialist(_) -> ok. -spec to_json(#calendar_specialist{}) -> map(). to_json(S) -> #{ id => S#calendar_specialist.id, calendar_id => S#calendar_specialist.calendar_id, user_id => S#calendar_specialist.user_id, name => S#calendar_specialist.name, specialization => S#calendar_specialist.specialization, status => S#calendar_specialist.status, added_at => handler_utils:datetime_to_iso8601(S#calendar_specialist.added_at), updated_at => handler_utils:datetime_to_iso8601(S#calendar_specialist.updated_at) }. %%%=================================================================== %%% Internal %%%=================================================================== require_owner_commercial(OwnerId, CalendarId) -> case core_calendar:get_by_id(CalendarId) of {ok, #calendar{owner_id = OwnerId, type = commercial, status = active} = Cal} -> {ok, Cal}; {ok, #calendar{owner_id = OwnerId, type = personal}} -> {error, not_commercial}; {ok, _} -> {error, access_denied}; Error -> Error end. owner_display_name(OwnerId) -> case core_user:get_by_id(OwnerId) of {ok, #user{nickname = Nick}} when is_binary(Nick), Nick =/= <<>> -> Nick; {ok, #user{email = Email}} when is_binary(Email), Email =/= <<>> -> Email; _ -> <<"Owner">> end.