Add webpush front-end support

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2021-05-06 18:39:59 +02:00
parent f1aac86bfb
commit 2c29a837ad
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
6 changed files with 99 additions and 0 deletions

View File

@ -83,6 +83,10 @@ export const CONFIG = gql`
instanceFeeds {
enabled
}
webPush {
enabled
publicKey
}
}
}
`;
@ -159,3 +163,14 @@ export const TIMEZONES = gql`
}
}
`;
export const WEB_PUSH = gql`
query {
config {
webPush {
enabled
publicKey
}
}
}
`;

View File

@ -0,0 +1,47 @@
import apolloProvider from "@/vue-apollo";
import ApolloClient from "apollo-client";
import { NormalizedCacheObject } from "apollo-cache-inmemory";
import { WEB_PUSH } from "../graphql/config";
import { IConfig } from "../types/config.model";
function urlBase64ToUint8Array(base64String: string): Uint8Array {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
export async function subscribeUserToPush(): Promise<PushSubscription | null> {
const registration = await navigator.serviceWorker.register(
"/service-worker.js"
);
const client = apolloProvider.defaultClient as ApolloClient<NormalizedCacheObject>;
const { data } = await client.mutate<{ config: IConfig }>({
mutation: WEB_PUSH,
});
if (data?.config?.webPush?.enabled && data?.config?.webPush?.publicKey) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
data?.config?.webPush?.publicKey
),
};
const pushSubscription = await registration.pushManager.subscribe(
subscribeOptions
);
console.log(
"Received PushSubscription: ",
JSON.stringify(pushSubscription)
);
return pushSubscription;
}
return null;
}

View File

@ -97,4 +97,8 @@ export interface IConfig {
instanceFeeds: {
enabled: boolean;
};
webPush: {
enabled: boolean;
publicKey: string;
};
}

View File

@ -15,6 +15,16 @@
</ul>
</nav>
<section>
<div class="setting-title">
<h2>{{ $t("Participation notifications") }}</h2>
</div>
<b-button
icon-left="rss"
@click="subscribeToWebPush"
v-if="!canShowWebPush"
>{{ $t("WebPush") }}</b-button
>
<span v-else>{{ $t("You can't use webpush in this browser.") }}</span>
<div class="setting-title">
<h2>{{ $t("Participation notifications") }}</h2>
</div>
@ -202,6 +212,7 @@ import { IUser } from "../../types/current-user.model";
import RouteName from "../../router/name";
import { IFeedToken } from "@/types/feedtoken.model";
import { CREATE_FEED_TOKEN, DELETE_FEED_TOKEN } from "@/graphql/feed_tokens";
import { subscribeUserToPush } from "../../services/push-subscription";
@Component({
apollo: {
@ -305,6 +316,17 @@ export default class Notifications extends Vue {
this.feedTokens.push(newToken);
}
async subscribeToWebPush(): Promise<void> {
if (window.isSecureContext && navigator.serviceWorker) {
const a = await subscribeUserToPush();
console.log(a);
}
}
canShowWebPush(): boolean {
return !!window.isSecureContext && !!navigator.serviceWorker;
}
private async deleteFeedToken(token: string): Promise<void> {
await this.$apollo.mutate({
mutation: DELETE_FEED_TOKEN,

View File

@ -142,6 +142,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
},
instance_feeds: %{
enabled: Config.get([:instance, :enable_instance_feeds])
},
web_push: %{
enabled: !is_nil(Application.get_env(:web_push_encryption, :vapid_details)),
public_key:
get_in(Application.get_env(:web_push_encryption, :vapid_details), [:public_key])
}
}
end

View File

@ -64,6 +64,7 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
field(:auth, :auth, description: "The instance auth methods")
field(:instance_feeds, :instance_feeds, description: "The instance's feed settings")
field(:web_push, :web_push, description: "Web Push settings for the instance")
end
@desc """
@ -299,6 +300,11 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
field(:enabled, :boolean, description: "Whether the instance-wide feeds are enabled")
end
object :web_push do
field(:enabled, :boolean, description: "Whether the WebPush feature is enabled")
field(:public_key, :string, description: "The server's public WebPush VAPID key")
end
object :config_queries do
@desc "Get the instance config"
field :config, :config do