From 994ef652005f8b998e96ce5c6156d87a63d85856 Mon Sep 17 00:00:00 2001
From: Paul <paulmakles@gmail.com>
Date: Fri, 25 Jun 2021 12:37:59 +0100
Subject: [PATCH] Notifications: Block muted channels from push notifs.

---
 src/context/revoltjs/Notifications.tsx | 10 ++-------
 src/redux/reducers/auth.ts             |  2 +-
 src/redux/reducers/locale.ts           |  2 +-
 src/redux/reducers/notifications.ts    | 18 +++++++++++++++-
 src/redux/reducers/queue.ts            |  2 +-
 src/redux/reducers/server_config.ts    |  2 +-
 src/redux/reducers/settings.ts         |  6 +++---
 src/redux/reducers/sync.ts             |  8 +++----
 src/redux/reducers/unreads.ts          |  2 +-
 src/sw.ts                              | 30 +++++++++++++++++++-------
 10 files changed, 53 insertions(+), 29 deletions(-)

diff --git a/src/context/revoltjs/Notifications.tsx b/src/context/revoltjs/Notifications.tsx
index d9f4f1f..7becc00 100644
--- a/src/context/revoltjs/Notifications.tsx
+++ b/src/context/revoltjs/Notifications.tsx
@@ -8,7 +8,7 @@ import { connectState } from "../../redux/connector";
 import { Message, SYSTEM_USER_ID, User } from "revolt.js";
 import { NotificationOptions } from "../../redux/reducers/settings";
 import { Route, Switch, useHistory, useParams } from "react-router-dom";
-import { getNotificationState, Notifications } from "../../redux/reducers/notifications";
+import { getNotificationState, Notifications, shouldNotify } from "../../redux/reducers/notifications";
 
 interface Props {
     options?: NotificationOptions;
@@ -49,13 +49,7 @@ function Notifier({ options, notifs }: Props) {
         if (author?.relationship === Users.Relationship.Blocked) return;
 
         const notifState = getNotificationState(notifs, channel);
-        switch (notifState) {
-            case 'muted':
-            case 'none': return;
-            case 'mention': {
-                if (!msg.mentions?.includes(client.user!._id)) return;
-            }
-        }
+        if (!shouldNotify(notifState, msg, client.user!._id)) return;
 
         playSound('message');
         if (!showNotification) return;
diff --git a/src/redux/reducers/auth.ts b/src/redux/reducers/auth.ts
index 38cd4df..c309e4f 100644
--- a/src/redux/reducers/auth.ts
+++ b/src/redux/reducers/auth.ts
@@ -1,4 +1,4 @@
-import { Auth } from "revolt.js/dist/api/objects";
+import type { Auth } from "revolt.js/dist/api/objects";
 
 export interface AuthState {
     accounts: {
diff --git a/src/redux/reducers/locale.ts b/src/redux/reducers/locale.ts
index 416da63..6146dd5 100644
--- a/src/redux/reducers/locale.ts
+++ b/src/redux/reducers/locale.ts
@@ -1,5 +1,5 @@
 import { Language } from "../../context/Locale";
-import { SyncUpdateAction } from "./sync";
+import type { SyncUpdateAction } from "./sync";
 
 export type LocaleAction =
     | { type: undefined }
diff --git a/src/redux/reducers/notifications.ts b/src/redux/reducers/notifications.ts
index 2ca5b03..6ffd352 100644
--- a/src/redux/reducers/notifications.ts
+++ b/src/redux/reducers/notifications.ts
@@ -1,4 +1,5 @@
-import { Channel } from "revolt.js";
+import type { Channel, Message } from "revolt.js";
+import type { SyncUpdateAction } from "./sync";
 
 export type NotificationState = 'all' | 'mention' | 'none' | 'muted';
 
@@ -18,6 +19,18 @@ export function getNotificationState(notifications: Notifications, channel: Chan
     return notifications[channel._id] ?? DEFAULT_STATES[channel.channel_type];
 }
 
+export function shouldNotify(state: NotificationState, message: Message, user_id: string) {
+    switch (state) {
+        case 'muted':
+        case 'none': return false;
+        case 'mention': {
+            if (!message.mentions?.includes(user_id)) return false;
+        }
+    }
+
+    return true;
+}
+
 export type NotificationsAction =
     | { type: undefined }
     | {
@@ -29,6 +42,7 @@ export type NotificationsAction =
         type: "NOTIFICATIONS_REMOVE";
         key: string;
       }
+    | SyncUpdateAction
     | {
         type: "RESET";
       };
@@ -48,6 +62,8 @@ export function notifications(
                 const { [action.key]: _, ...newState } = state;
                 return newState;
             }
+        case "SYNC_UPDATE":
+            return action.update.notifications?.[1] ?? state;
         case "RESET":
             return {};
         default:
diff --git a/src/redux/reducers/queue.ts b/src/redux/reducers/queue.ts
index 3bcbec5..ef64578 100644
--- a/src/redux/reducers/queue.ts
+++ b/src/redux/reducers/queue.ts
@@ -1,4 +1,4 @@
-import { MessageObject } from "../../context/revoltjs/util";
+import type { MessageObject } from "../../context/revoltjs/util";
 
 export enum QueueStatus {
     SENDING = "sending",
diff --git a/src/redux/reducers/server_config.ts b/src/redux/reducers/server_config.ts
index 9e14fb0..6046c5d 100644
--- a/src/redux/reducers/server_config.ts
+++ b/src/redux/reducers/server_config.ts
@@ -1,4 +1,4 @@
-import { Core } from "revolt.js/dist/api/objects";
+import type { Core } from "revolt.js/dist/api/objects";
 
 export type ConfigAction =
     | { type: undefined }
diff --git a/src/redux/reducers/settings.ts b/src/redux/reducers/settings.ts
index a37d7ef..bd7e822 100644
--- a/src/redux/reducers/settings.ts
+++ b/src/redux/reducers/settings.ts
@@ -1,7 +1,7 @@
 import { filter } from ".";
-import { SyncUpdateAction } from "./sync";
-import { Sounds } from "../../assets/sounds/Audio";
-import { Theme, ThemeOptions } from "../../context/Theme";
+import type { SyncUpdateAction } from "./sync";
+import type { Sounds } from "../../assets/sounds/Audio";
+import type { Theme, ThemeOptions } from "../../context/Theme";
 import { setEmojiPack } from "../../components/common/Emoji";
 
 export type SoundOptions = {
diff --git a/src/redux/reducers/sync.ts b/src/redux/reducers/sync.ts
index 0e2c811..099d98d 100644
--- a/src/redux/reducers/sync.ts
+++ b/src/redux/reducers/sync.ts
@@ -1,7 +1,7 @@
-import { AppearanceOptions } from "./settings";
-import { Language } from "../../context/Locale";
-import { ThemeOptions } from "../../context/Theme";
-import { Notifications } from "./notifications";
+import type { AppearanceOptions } from "./settings";
+import type { Language } from "../../context/Locale";
+import type { ThemeOptions } from "../../context/Theme";
+import type { Notifications } from "./notifications";
 
 export type SyncKeys = "theme" | "appearance" | "locale" | "notifications";
 
diff --git a/src/redux/reducers/unreads.ts b/src/redux/reducers/unreads.ts
index 290afdc..1f1b2fb 100644
--- a/src/redux/reducers/unreads.ts
+++ b/src/redux/reducers/unreads.ts
@@ -1,4 +1,4 @@
-import { Sync } from "revolt.js/dist/api/objects";
+import type { Sync } from "revolt.js/dist/api/objects";
 
 export interface Unreads {
     [key: string]: Partial<Omit<Sync.ChannelUnread, "_id">>;
diff --git a/src/sw.ts b/src/sw.ts
index 2684816..7d58aba 100644
--- a/src/sw.ts
+++ b/src/sw.ts
@@ -3,6 +3,9 @@ import { precacheAndRoute } from 'workbox-precaching'
 import { Server } from 'revolt.js/dist/api/objects'
 import { Channel, Message, User } from 'revolt.js'
 import { IDBPDatabase, openDB } from 'idb'
+import { getItem } from 'localforage'
+import type { State } from './redux'
+import { getNotificationState, shouldNotify } from './redux/reducers/notifications'
 
 declare let self: ServiceWorkerGlobalScope
 
@@ -34,12 +37,18 @@ function decodeTime(id: string) {
     return time;
 }
 
-const base_url = `https://autumn.revolt.chat`;
 self.addEventListener("push", event => {
 	async function process() {
 		if (event.data === null) return;
 		let data: Message = event.data.json();
 
+		let item = await localStorage.getItem('state');
+		if (!item) return;
+
+		const state: State = JSON.parse(item);
+		const autumn_url = state.config.features.autumn.url;
+		const user_id = state.auth.active!;
+
 		let db: IDBPDatabase;
 		try {
 			// Match RevoltClient.tsx#L55
@@ -65,19 +74,24 @@ self.addEventListener("push", event => {
 			}
 		}
 		
+		let channel = await get<Channel>('channels', data.channel);
+		let user = await get<User>('users', data.author);
+
+		if (channel) {
+			const notifs = getNotificationState(state.notifications, channel);
+			if (!shouldNotify(notifs, data, user_id)) return;
+		}
+		
+		let title = `@${data.author}`;
+		let username = user?.username ?? data.author;
 		let image;
 		if (data.attachments) {
 			let attachment = data.attachments[0];
 			if (attachment.metadata.type === "Image") {
-				image = `${base_url}/${attachment.tag}/${attachment._id}`;
+				image = `${autumn_url}/${attachment.tag}/${attachment._id}`;
 			}
 		}
 		
-		let title = `@${data.author}`;
-		let channel = await get<Channel>('channels', data.channel);
-		let user = await get<User>('users', data.author);
-		let username = user?.username ?? data.author;
-		
 		switch (channel?.channel_type) {
 			case "SavedMessages": break;
 			case "DirectMessage": title = `@${username}`; break;
@@ -97,7 +111,7 @@ self.addEventListener("push", event => {
 		}
 		
 		await self.registration.showNotification(title, {
-			icon: user?.avatar ? `${base_url}/${user.avatar.tag}/${user.avatar._id}` : `https://api.revolt.chat/users/${data.author}/default_avatar`,
+			icon: user?.avatar ? `${autumn_url}/${user.avatar.tag}/${user.avatar._id}` : `https://api.revolt.chat/users/${data.author}/default_avatar`,
 			image,
 			body: typeof data.content === "string" ? data.content : JSON.stringify(data.content),
 			timestamp: decodeTime(data._id),
-- 
GitLab