%%%------------------------------------------------------------------- %%% @doc Хранение follow чужих календарей (уникальность calendar_id+user_id). %%% @end %%%------------------------------------------------------------------- -module(core_calendar_follow). -include("records.hrl"). -export([follow/2, unfollow/2, is_following/2, list_by_user/1, list_by_calendar/1, delete_by_calendar/1]). %%%------------------------------------------------------------------- %%% @doc Подписаться на календарь. Идемпотентно, если уже follow. %%% @end %%%------------------------------------------------------------------- -spec follow(CalendarId :: binary(), UserId :: binary()) -> {ok, #calendar_follow{}} | {error, term()}. follow(CalendarId, UserId) -> Now = calendar:universal_time(), F = fun() -> case find(CalendarId, UserId) of [#calendar_follow{} = Existing] -> {ok, Existing}; [] -> Rec = #calendar_follow{ id = infra_utils:generate_id(16), calendar_id = CalendarId, user_id = UserId, created_at = Now }, mnesia:write(Rec), {ok, Rec} end end, case mnesia:transaction(F) of {atomic, Result} -> Result; {aborted, Reason} -> {error, Reason} end. %%%------------------------------------------------------------------- %%% @doc Отписаться. Идемпотентно, если follow нет. %%% @end %%%------------------------------------------------------------------- -spec unfollow(CalendarId :: binary(), UserId :: binary()) -> ok | {error, term()}. unfollow(CalendarId, UserId) -> F = fun() -> case find(CalendarId, UserId) of [] -> ok; [#calendar_follow{id = Id}] -> mnesia:delete({calendar_follow, Id}), ok end end, case mnesia:transaction(F) of {atomic, ok} -> ok; {aborted, Reason} -> {error, Reason} end. %%%------------------------------------------------------------------- %%% @doc Есть ли follow у пользователя. %%% @end %%%------------------------------------------------------------------- -spec is_following(UserId :: binary(), CalendarId :: binary()) -> boolean(). is_following(UserId, CalendarId) -> case mnesia:dirty_match_object( #calendar_follow{calendar_id = CalendarId, user_id = UserId, _ = '_'}) of [] -> false; _ -> true end. %%%------------------------------------------------------------------- %%% @doc Все follow пользователя. %%% @end %%%------------------------------------------------------------------- -spec list_by_user(UserId :: binary()) -> [#calendar_follow{}]. list_by_user(UserId) -> mnesia:dirty_match_object(#calendar_follow{user_id = UserId, _ = '_'}). %%%------------------------------------------------------------------- %%% @doc Все follow календаря. %%% @end %%%------------------------------------------------------------------- -spec list_by_calendar(CalendarId :: binary()) -> [#calendar_follow{}]. list_by_calendar(CalendarId) -> mnesia:dirty_match_object(#calendar_follow{calendar_id = CalendarId, _ = '_'}). %%%------------------------------------------------------------------- %%% @doc Удалить все follow календаря (при удалении calendar). %%% @end %%%------------------------------------------------------------------- -spec delete_by_calendar(CalendarId :: binary()) -> ok. delete_by_calendar(CalendarId) -> F = fun() -> lists:foreach( fun(#calendar_follow{id = Id}) -> mnesia:delete({calendar_follow, Id}) end, mnesia:match_object(#calendar_follow{calendar_id = CalendarId, _ = '_'})), ok end, case mnesia:transaction(F) of {atomic, ok} -> ok; {aborted, Reason} -> error({delete_follows_failed, Reason}) end. %%%=================================================================== %%% Internal %%%=================================================================== find(CalendarId, UserId) -> mnesia:match_object(#calendar_follow{calendar_id = CalendarId, user_id = UserId, _ = '_'}).