From df71dbb0242d763695ea8a33d0b2262c74b050d0 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Fri, 18 Sep 2020 22:18:21 +0900
Subject: [PATCH] Resolve #6692 (#6703)

---
 .../1600353287890-mutingNotificationTypes.ts  | 20 +++++++++++++++++++
 src/client/app.vue                            |  3 +--
 src/client/components/notifications.vue       |  7 +++----
 src/client/deck.vue                           |  3 +--
 src/client/pages/my-settings/index.vue        |  8 +++++---
 src/models/entities/user-profile.ts           |  4 ++--
 src/models/repositories/user.ts               |  2 +-
 src/server/api/endpoints/i/update.ts          |  4 ++--
 src/services/create-notification.ts           |  2 +-
 9 files changed, 36 insertions(+), 17 deletions(-)
 create mode 100644 migration/1600353287890-mutingNotificationTypes.ts

diff --git a/migration/1600353287890-mutingNotificationTypes.ts b/migration/1600353287890-mutingNotificationTypes.ts
new file mode 100644
index 0000000000..914bad8e3f
--- /dev/null
+++ b/migration/1600353287890-mutingNotificationTypes.ts
@@ -0,0 +1,20 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class mutingNotificationTypes1600353287890 implements MigrationInterface {
+    name = 'mutingNotificationTypes1600353287890'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "includingNotificationTypes"`);
+        await queryRunner.query(`DROP TYPE "public"."user_profile_includingnotificationtypes_enum"`);
+        await queryRunner.query(`CREATE TYPE "user_profile_mutingnotificationtypes_enum" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app')`);
+        await queryRunner.query(`ALTER TABLE "user_profile" ADD "mutingNotificationTypes" "user_profile_mutingnotificationtypes_enum" array NOT NULL DEFAULT '{}'`);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "mutingNotificationTypes"`);
+        await queryRunner.query(`DROP TYPE "user_profile_mutingnotificationtypes_enum"`);
+        await queryRunner.query(`CREATE TYPE "public"."user_profile_includingnotificationtypes_enum" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app')`);
+        await queryRunner.query(`ALTER TABLE "user_profile" ADD "includingNotificationTypes" "user_profile_includingnotificationtypes_enum" array`);
+    }
+
+}
diff --git a/src/client/app.vue b/src/client/app.vue
index c10ba9c9d9..3453baa280 100644
--- a/src/client/app.vue
+++ b/src/client/app.vue
@@ -328,8 +328,7 @@ export default Vue.extend({
 		},
 
 		async onNotification(notification) {
-			const t = this.$store.state.i.includingNotificationTypes;
-			if (!!t && !t.includes(notification.type)) {
+			if (this.$store.state.i.mutingNotificationTypes.includes(notification.type)) {
 				return;
 			}
 			if (document.visibilityState === 'visible') {
diff --git a/src/client/components/notifications.vue b/src/client/components/notifications.vue
index 07dee6354b..0e512e1967 100644
--- a/src/client/components/notifications.vue
+++ b/src/client/components/notifications.vue
@@ -58,7 +58,7 @@ export default Vue.extend({
 
 	computed: {
 		allIncludeTypes() {
-			return this.includeTypes ?? this.$store.state.i.includingNotificationTypes;
+			return this.includeTypes ?? notificationTypes.filter(x => !this.$store.state.i.mutingNotificationTypes.includes(x));
 		}
 	},
 
@@ -66,7 +66,7 @@ export default Vue.extend({
 		includeTypes() {
 			this.reload();
 		},
-		'$store.state.i.includingNotificationTypes'() {
+		'$store.state.i.mutingNotificationTypes'() {
 			if (this.includeTypes === null) {
 				this.reload();
 			}
@@ -84,8 +84,7 @@ export default Vue.extend({
 
 	methods: {
 		onNotification(notification) {
-			// 
-			const isMuted = !!this.allIncludeTypes && !this.allIncludeTypes.includes(notification.type);
+			const isMuted = !this.allIncludeTypes.includes(notification.type);
 			if (isMuted || document.visibilityState === 'visible') {
 				this.$root.stream.send('readNotification', {
 					id: notification.id
diff --git a/src/client/deck.vue b/src/client/deck.vue
index dc662801f0..c383a1b15c 100644
--- a/src/client/deck.vue
+++ b/src/client/deck.vue
@@ -161,8 +161,7 @@ export default Vue.extend({
 		},
 
 		async onNotification(notification) {
-			const t = this.$store.state.i.includingNotificationTypes;
-			if (!!t && !t.includes(notification.type)) {
+			if (this.$store.state.i.mutingNotificationTypes.includes(notification.type)) {
 				return;
 			}
 
diff --git a/src/client/pages/my-settings/index.vue b/src/client/pages/my-settings/index.vue
index 7da9f24c75..ae4ad4dff5 100644
--- a/src/client/pages/my-settings/index.vue
+++ b/src/client/pages/my-settings/index.vue
@@ -58,6 +58,7 @@ import XIntegration from './integration.vue';
 import XApi from './api.vue';
 import MkButton from '../../components/ui/button.vue';
 import MkSwitch from '../../components/ui/switch.vue';
+import { notificationTypes } from '../../../types';
 
 export default Vue.extend({
 	metaInfo() {
@@ -114,14 +115,15 @@ export default Vue.extend({
 		},
 
 		async configure() {
+			const includingTypes = notificationTypes.filter(x => !this.$store.state.i.mutingNotificationTypes.includes(x));
 			this.$root.new(await import('../../components/notification-setting-window.vue').then(m => m.default), {
-				includingTypes: this.$store.state.i.includingNotificationTypes,
+				includingTypes,
 				showGlobalToggle: false,
 			}).$on('ok', async ({ includingTypes: value }: any) => {
 				await this.$root.api('i/update', {
-					includingNotificationTypes: value,
+					mutingNotificationTypes: notificationTypes.filter(x => !value.includes(x)),
 				}).then(i => {
-					this.$store.state.i.includingNotificationTypes = i.includingNotificationTypes;
+					this.$store.state.i.mutingNotificationTypes = i.mutingNotificationTypes;
 				}).catch(err => {
 					this.$root.dialog({
 						type: 'error',
diff --git a/src/models/entities/user-profile.ts b/src/models/entities/user-profile.ts
index 0eeed1b40e..7195c20ffe 100644
--- a/src/models/entities/user-profile.ts
+++ b/src/models/entities/user-profile.ts
@@ -162,9 +162,9 @@ export class UserProfile {
 	@Column('enum', {
 		enum: notificationTypes,
 		array: true,
-		nullable: true,
+		default: [],
 	})
-	public includingNotificationTypes: typeof notificationTypes[number][] | null;
+	public mutingNotificationTypes: typeof notificationTypes[number][];
 
 	//#region Denormalized fields
 	@Index()
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
index b1b084b740..7ea4d42bcb 100644
--- a/src/models/repositories/user.ts
+++ b/src/models/repositories/user.ts
@@ -248,7 +248,7 @@ export class UserRepository extends Repository<User> {
 				hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id),
 				integrations: profile!.integrations,
 				mutedWords: profile!.mutedWords,
-				includingNotificationTypes: profile?.includingNotificationTypes,
+				mutingNotificationTypes: profile?.mutingNotificationTypes,
 			} : {}),
 
 			...(opts.includeSecrets ? {
diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts
index 327e303a66..2029f2b4b6 100644
--- a/src/server/api/endpoints/i/update.ts
+++ b/src/server/api/endpoints/i/update.ts
@@ -149,7 +149,7 @@ export const meta = {
 			validator: $.optional.arr($.arr($.str))
 		},
 
-		includingNotificationTypes: {
+		mutingNotificationTypes: {
 			validator: $.optional.arr($.str.or(notificationTypes as unknown as string[]))
 		},
 	},
@@ -206,7 +206,7 @@ export default define(meta, async (ps, user, token) => {
 		profileUpdates.mutedWords = ps.mutedWords;
 		profileUpdates.enableWordMute = ps.mutedWords.length > 0;
 	}
-	if (ps.includingNotificationTypes !== undefined) profileUpdates.includingNotificationTypes = ps.includingNotificationTypes as typeof notificationTypes[number][];
+	if (ps.mutingNotificationTypes !== undefined) profileUpdates.mutingNotificationTypes = ps.mutingNotificationTypes as typeof notificationTypes[number][];
 	if (typeof ps.isLocked === 'boolean') updates.isLocked = ps.isLocked;
 	if (typeof ps.isBot === 'boolean') updates.isBot = ps.isBot;
 	if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot;
diff --git a/src/services/create-notification.ts b/src/services/create-notification.ts
index 7471c349ee..5dddaa5727 100644
--- a/src/services/create-notification.ts
+++ b/src/services/create-notification.ts
@@ -16,7 +16,7 @@ export async function createNotification(
 
 	const profile = await UserProfiles.findOne({ userId: notifieeId });
 
-	const isMuted = !(profile?.includingNotificationTypes == null || profile?.includingNotificationTypes.includes(type));
+	const isMuted = profile?.mutingNotificationTypes.includes(type);
 
 	// Create notification
 	const notification = await Notifications.save({