%%%------------------------------------------------------------------- %%% @doc Web Push subscriptions (Back#75). %%% @end %%%------------------------------------------------------------------- -module(core_push_subscription). -export([upsert/4, list_by_user/1, delete_by_endpoint/2, delete_by_id/1, get_by_endpoint/1]). -include("records.hrl"). -spec upsert(binary(), binary(), binary(), binary()) -> {ok, #push_subscription{}} | {error, term()}. upsert(UserId, Endpoint, P256dh, Auth) -> Now = calendar:universal_time(), case get_by_endpoint(Endpoint) of {ok, #push_subscription{} = Existing} -> Rec = Existing#push_subscription{ user_id = UserId, p256dh = P256dh, auth = Auth, created_at = Now }, case mnesia:transaction(fun() -> mnesia:write(Rec) end) of {atomic, ok} -> {ok, Rec}; {aborted, Reason} -> {error, Reason} end; {error, not_found} -> Rec = #push_subscription{ id = infra_utils:generate_id(16), user_id = UserId, endpoint = Endpoint, p256dh = P256dh, auth = Auth, created_at = Now }, case mnesia:transaction(fun() -> mnesia:write(Rec) end) of {atomic, ok} -> {ok, Rec}; {aborted, Reason} -> {error, Reason} end end. -spec list_by_user(binary()) -> [#push_subscription{}]. list_by_user(UserId) -> mnesia:dirty_match_object(#push_subscription{user_id = UserId, _ = '_'}). -spec get_by_endpoint(binary()) -> {ok, #push_subscription{}} | {error, not_found}. get_by_endpoint(Endpoint) -> case mnesia:dirty_index_read(push_subscription, Endpoint, #push_subscription.endpoint) of [Rec | _] -> {ok, Rec}; [] -> case mnesia:dirty_match_object(#push_subscription{endpoint = Endpoint, _ = '_'}) of [Rec | _] -> {ok, Rec}; [] -> {error, not_found} end end. -spec delete_by_endpoint(binary(), binary()) -> ok | {error, not_found | forbidden}. delete_by_endpoint(UserId, Endpoint) -> case get_by_endpoint(Endpoint) of {ok, #push_subscription{id = Id, user_id = UserId}} -> delete_by_id(Id); {ok, #push_subscription{}} -> {error, forbidden}; {error, not_found} -> {error, not_found} end. -spec delete_by_id(binary()) -> ok | {error, term()}. delete_by_id(Id) -> case mnesia:transaction(fun() -> mnesia:delete({push_subscription, Id}) end) of {atomic, ok} -> ok; {aborted, Reason} -> {error, Reason} end.