Add Push notifications backend support

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2021-05-06 12:27:04 +02:00
parent 4f6e203ced
commit 9f5e3a39ec
14 changed files with 321 additions and 26 deletions

View File

@@ -0,0 +1,49 @@
defmodule Mobilizon.Users.PushSubscription do
use Ecto.Schema
alias Mobilizon.Users.User
import Ecto.Changeset
schema "user_push_subscriptions" do
field(:digest, :string)
belongs_to(:user, User)
embeds_one :data, Data, on_replace: :delete do
field(:endpoint, :string)
embeds_one :keys, Keys, on_replace: :delete do
field(:auth, :string)
field(:p256dh, :string)
end
end
timestamps()
end
@doc false
def changeset(push_subscription, attrs) do
push_subscription
|> cast(attrs, [:user_id])
|> cast_embed(:data, with: &cast_data/2)
|> put_change(:digest, compute_digest(attrs.data))
|> validate_required([:digest, :user_id, :data])
end
defp cast_data(schema, attrs) do
schema
|> cast(attrs, [:endpoint])
|> cast_embed(:keys, with: &cast_keys/2)
|> validate_required([:endpoint, :keys])
end
defp cast_keys(schema, attrs) do
schema
|> cast(attrs, [:auth, :p256dh])
|> validate_required([:auth, :p256dh])
end
defp compute_digest(data) do
:sha256
|> :crypto.hash(data)
|> Base.encode16()
end
end

View File

@@ -14,6 +14,8 @@ defmodule Mobilizon.Users.Setting do
notification_before_event: boolean,
notification_pending_participation: NotificationPendingNotificationDelay.t(),
notification_pending_membership: NotificationPendingNotificationDelay.t(),
group_notifications: NotificationPendingNotificationDelay.t(),
last_notification_sent: DateTime.t(),
user: User.t()
}
@@ -25,7 +27,9 @@ defmodule Mobilizon.Users.Setting do
:notification_each_week,
:notification_before_event,
:notification_pending_participation,
:notification_pending_membership
:notification_pending_membership,
:group_notifications,
:last_notification_sent
]
@attrs @required_attrs ++ @optional_attrs
@@ -47,6 +51,9 @@ defmodule Mobilizon.Users.Setting do
default: :one_day
)
field(:group_notifications, NotificationPendingNotificationDelay, default: :one_day)
field(:last_notification_sent, :utc_datetime)
embeds_one :location, Location, on_replace: :update, primary_key: false do
field(:name, :string)
field(:range, :integer)

View File

@@ -13,7 +13,7 @@ defmodule Mobilizon.Users do
alias Mobilizon.{Crypto, Events}
alias Mobilizon.Events.FeedToken
alias Mobilizon.Storage.{Page, Repo}
alias Mobilizon.Users.{Setting, User}
alias Mobilizon.Users.{PushSubscription, Setting, User}
defenum(UserRole, :user_role, [:administrator, :moderator, :user])
@@ -405,6 +405,80 @@ defmodule Mobilizon.Users do
Setting.changeset(setting, %{})
end
@doc """
Get a paginated list of all of a user's subscriptions
"""
@spec list_user_push_subscriptions(String.t() | integer(), integer() | nil, integer() | nil) ::
Page.t()
def list_user_push_subscriptions(user_id, page \\ nil, limit \\ nil) do
PushSubscription
|> where([p], p.user_id == ^user_id)
|> preload([:user])
|> Page.build_page(page, limit)
end
@doc """
Get a push subscription by their ID
"""
@spec get_push_subscription(String.t() | integer()) :: PushSubscription.t() | nil
def get_push_subscription(push_subscription_id) do
PushSubscription
|> Repo.get(push_subscription_id)
|> Repo.preload([:user])
end
@doc """
Creates a push subscription.
## Examples
iex> create_push_subscription(%{field: value})
{:ok, %PushSubscription{}}
iex> create_push_subscription(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_push_subscription(attrs \\ %{}) do
%PushSubscription{}
|> PushSubscription.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a push subscription.
## Examples
iex> update_push_subscription(push_subscription, %{field: new_value})
{:ok, %PushSubscription{}}
iex> update_push_subscription(push_subscription, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_push_subscription(%PushSubscription{} = push_subscription, attrs) do
push_subscription
|> PushSubscription.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a push subscription.
## Examples
iex> delete_push_subscription(push_subscription)
{:ok, %PushSubscription{}}
iex> delete_push_subscription(push_subscription)
{:error, %Ecto.Changeset{}}
"""
def delete_push_subscription(%PushSubscription{} = push_subscription) do
Repo.delete(push_subscription)
end
@spec user_by_email_query(String.t(), boolean | nil, boolean()) :: Ecto.Query.t()
defp user_by_email_query(email, activated, unconfirmed) do
User