From bdae03fc52cebdf2ee4c65a63178866b5fbb6c16 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 7 May 2021 09:06:45 +0200 Subject: [PATCH] fixup! Add webpush front-end support Signed-off-by: Thomas Citharel --- js/src/service-worker.ts | 31 ++++++++++++++++++++++ js/src/services/push-subscription.ts | 11 +++++--- js/src/views/Settings/Notifications.vue | 13 +++++++-- lib/graphql/resolvers/push_subscription.ex | 2 +- lib/mobilizon/users/push_subscription.ex | 4 +++ lib/service/notifier/push.ex | 4 +-- 6 files changed, 56 insertions(+), 9 deletions(-) diff --git a/js/src/service-worker.ts b/js/src/service-worker.ts index ea958ccbe..029da54ee 100644 --- a/js/src/service-worker.ts +++ b/js/src/service-worker.ts @@ -75,3 +75,34 @@ registerRoute( ], }) ); + +self.addEventListener("push", async (event: any) => { + console.log("received push", event); + const options = { + body: "Ceci est une notification envoyée par Mobilizon !", + icon: "images/notification-flat.png", + vibrate: [100, 50, 100], + data: { + dateOfArrival: Date.now(), + primaryKey: 1, + }, + actions: [ + { + action: "explore", + title: "Go to the site", + icon: "images/checkmark.png", + }, + { + action: "close", + title: "Close the notification", + icon: "images/xmark.png", + }, + ], + }; + + event.waitUntil( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + self.registration.showNotification("Push Notification", options) + ); +}); diff --git a/js/src/services/push-subscription.ts b/js/src/services/push-subscription.ts index 91fc78168..5d0375829 100644 --- a/js/src/services/push-subscription.ts +++ b/js/src/services/push-subscription.ts @@ -18,11 +18,9 @@ function urlBase64ToUint8Array(base64String: string): Uint8Array { } export async function subscribeUserToPush(): Promise { - const registration = await navigator.serviceWorker.register( - "/service-worker.js" - ); - const client = apolloProvider.defaultClient as ApolloClient; + + const registration = await navigator.serviceWorker.ready; const { data } = await client.mutate<{ config: IConfig }>({ mutation: WEB_PUSH, }); @@ -45,3 +43,8 @@ export async function subscribeUserToPush(): Promise { } return null; } + +export async function isSubscribed(): Promise { + const registration = await navigator.serviceWorker.ready; + return (await registration.pushManager.getSubscription()) !== null; +} diff --git a/js/src/views/Settings/Notifications.vue b/js/src/views/Settings/Notifications.vue index e064e67a4..bcb385951 100644 --- a/js/src/views/Settings/Notifications.vue +++ b/js/src/views/Settings/Notifications.vue @@ -18,6 +18,7 @@

{{ $t("Participation notifications") }}

+ { if (this.canShowWebPush()) { const subscription = await subscribeUserToPush(); + console.log("subscription", subscription?.toJSON()); const { data } = await this.$apollo.mutate({ mutation: REGISTER_PUSH_MUTATION, variables: { - ...subscription, + ...subscription?.toJSON(), }, }); console.log(data); @@ -336,6 +341,10 @@ export default class Notifications extends Vue { return window.isSecureContext && !!navigator.serviceWorker; } + async isSubscribed(): Promise { + return await isSubscribed(); + } + private async deleteFeedToken(token: string): Promise { await this.$apollo.mutate({ mutation: DELETE_FEED_TOKEN, diff --git a/lib/graphql/resolvers/push_subscription.ex b/lib/graphql/resolvers/push_subscription.ex index 13510b0b1..fee85841f 100644 --- a/lib/graphql/resolvers/push_subscription.ex +++ b/lib/graphql/resolvers/push_subscription.ex @@ -25,7 +25,7 @@ defmodule Mobilizon.GraphQL.Resolvers.PushSubscription do def register_push_subscription(_parent, args, %{ context: %{current_user: %User{id: user_id}} }) do - case Users.create_push_subscription(Map.put(args, :user_id, user_id)) do + case Users.create_push_subscription(%{data: args, user_id: user_id}) do {:ok, %PushSubscription{}} -> {:ok, "OK"} diff --git a/lib/mobilizon/users/push_subscription.ex b/lib/mobilizon/users/push_subscription.ex index 0ea7fa777..903543d14 100644 --- a/lib/mobilizon/users/push_subscription.ex +++ b/lib/mobilizon/users/push_subscription.ex @@ -3,6 +3,7 @@ defmodule Mobilizon.Users.PushSubscription do alias Mobilizon.Users.User import Ecto.Changeset + @primary_key {:id, :binary_id, autogenerate: true} schema "user_push_subscriptions" do field(:digest, :string) belongs_to(:user, User) @@ -26,6 +27,7 @@ defmodule Mobilizon.Users.PushSubscription do |> cast_embed(:data, with: &cast_data/2) |> put_change(:digest, compute_digest(attrs.data)) |> validate_required([:digest, :user_id, :data]) + |> unique_constraint([:digest, :user_id], name: :user_push_subscriptions_user_id_digest_index) end defp cast_data(schema, attrs) do @@ -42,6 +44,8 @@ defmodule Mobilizon.Users.PushSubscription do end defp compute_digest(data) do + data = Jason.encode!(data) + :sha256 |> :crypto.hash(data) |> Base.encode16() diff --git a/lib/service/notifier/push.ex b/lib/service/notifier/push.ex index e9b7c0b94..8c779519e 100644 --- a/lib/service/notifier/push.ex +++ b/lib/service/notifier/push.ex @@ -19,12 +19,12 @@ defmodule Mobilizon.Service.Notifier.Push do @impl Notifier def send(%User{id: user_id} = _user, %Activity{} = activity, _opts) do %Page{elements: subscriptions} = Users.list_user_push_subscriptions(user_id, 1, 100) - Enum.each(subscriptions, &send_subscription(activity, &1)) + Enum.map(subscriptions, &send_subscription(activity, &1.data)) end @impl Notifier def send(%User{} = user, activities, opts) when is_list(activities) do - Enum.each(activities, &Push.send(user, &1, opts)) + Enum.map(activities, &Push.send(user, &1, opts)) end defp payload(%Activity{subject: subject}) do