fix: i/notificationsで古い通知タイプを許容するなど、古い通知タイプの清算 (#10042)
* wip
* fix
* create migration
* oops
* fix front const
* changelog
* fix type
* fix
* wip
* Revert "wip"
This reverts commit 6cdb3600e2.
* enumのこす
* fix
---------
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
			
			
This commit is contained in:
		| @@ -94,13 +94,6 @@ export class NotificationEntityService implements OnModuleInit { | ||||
| 				}), | ||||
| 				reaction: notification.reaction, | ||||
| 			} : {}), | ||||
| 			...(notification.type === 'pollVote' ? { // TODO: そのうち消す | ||||
| 				note: this.noteEntityService.pack(notification.note ?? notification.noteId!, { id: notification.notifieeId }, { | ||||
| 					detail: true, | ||||
| 					_hint_: options._hintForEachNotes_, | ||||
| 				}), | ||||
| 				choice: notification.choice, | ||||
| 			} : {}), | ||||
| 			...(notification.type === 'pollEnded' ? { | ||||
| 				note: this.noteEntityService.pack(notification.note ?? notification.noteId!, { id: notification.notifieeId }, { | ||||
| 					detail: true, | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { Entity, Index, JoinColumn, ManyToOne, Column, PrimaryColumn } from 'typeorm'; | ||||
| import { notificationTypes } from '@/types.js'; | ||||
| import { notificationTypes, obsoleteNotificationTypes } from '@/types.js'; | ||||
| import { id } from '../id.js'; | ||||
| import { User } from './User.js'; | ||||
| import { Note } from './Note.js'; | ||||
| @@ -58,7 +58,6 @@ export class Notification { | ||||
| 	 * renote - 投稿がRenoteされた | ||||
| 	 * quote - 投稿が引用Renoteされた | ||||
| 	 * reaction - 投稿にリアクションされた | ||||
| 	 * pollVote - 投稿のアンケートに投票された (廃止) | ||||
| 	 * pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した | ||||
| 	 * receiveFollowRequest - フォローリクエストされた | ||||
| 	 * followRequestAccepted - 自分の送ったフォローリクエストが承認された | ||||
| @@ -67,7 +66,10 @@ export class Notification { | ||||
| 	 */ | ||||
| 	@Index() | ||||
| 	@Column('enum', { | ||||
| 		enum: notificationTypes, | ||||
| 		enum: [ | ||||
| 			...notificationTypes, | ||||
| 			...obsoleteNotificationTypes, | ||||
| 		], | ||||
| 		comment: 'The type of the Notification.', | ||||
| 	}) | ||||
| 	public type: typeof notificationTypes[number]; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; | ||||
| import { ffVisibility, notificationTypes } from '@/types.js'; | ||||
| import { obsoleteNotificationTypes, ffVisibility, notificationTypes } from '@/types.js'; | ||||
| import { id } from '../id.js'; | ||||
| import { User } from './User.js'; | ||||
| import { Page } from './Page.js'; | ||||
| @@ -205,7 +205,7 @@ export class UserProfile { | ||||
| 		enum: [  | ||||
| 			...notificationTypes, | ||||
| 			// マイグレーションで削除が困難なので古いenumは残しておく | ||||
| 			'groupInvited', | ||||
| 			...obsoleteNotificationTypes, | ||||
| 		], | ||||
| 		array: true, | ||||
| 		default: [], | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { Brackets } from 'typeorm'; | ||||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import type { UsersRepository, FollowingsRepository, MutingsRepository, UserProfilesRepository, NotificationsRepository } from '@/models/index.js'; | ||||
| import { notificationTypes } from '@/types.js'; | ||||
| import { obsoleteNotificationTypes, notificationTypes } from '@/types.js'; | ||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { QueryService } from '@/core/QueryService.js'; | ||||
| import { NoteReadService } from '@/core/NoteReadService.js'; | ||||
| @@ -41,11 +41,12 @@ export const paramDef = { | ||||
| 		following: { type: 'boolean', default: false }, | ||||
| 		unreadOnly: { type: 'boolean', default: false }, | ||||
| 		markAsRead: { type: 'boolean', default: true }, | ||||
| 		// 後方互換のため、廃止された通知タイプも受け付ける | ||||
| 		includeTypes: { type: 'array', items: { | ||||
| 			type: 'string', enum: notificationTypes, | ||||
| 			type: 'string', enum: [...notificationTypes, ...obsoleteNotificationTypes], | ||||
| 		} }, | ||||
| 		excludeTypes: { type: 'array', items: { | ||||
| 			type: 'string', enum: notificationTypes, | ||||
| 			type: 'string', enum: [...notificationTypes, ...obsoleteNotificationTypes], | ||||
| 		} }, | ||||
| 	}, | ||||
| 	required: [], | ||||
| @@ -84,6 +85,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||
| 			if (notificationTypes.every(type => ps.excludeTypes?.includes(type))) { | ||||
| 				return []; | ||||
| 			} | ||||
|  | ||||
| 			const includeTypes = ps.includeTypes && ps.includeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][]; | ||||
| 			const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][]; | ||||
|  | ||||
| 			const followingQuery = this.followingsRepository.createQueryBuilder('following') | ||||
| 				.select('following.followeeId') | ||||
| 				.where('following.followerId = :followerId', { followerId: me.id }); | ||||
| @@ -143,10 +148,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||
| 				query.setParameters(followingQuery.getParameters()); | ||||
| 			} | ||||
|  | ||||
| 			if (ps.includeTypes && ps.includeTypes.length > 0) { | ||||
| 				query.andWhere('notification.type IN (:...includeTypes)', { includeTypes: ps.includeTypes }); | ||||
| 			} else if (ps.excludeTypes && ps.excludeTypes.length > 0) { | ||||
| 				query.andWhere('notification.type NOT IN (:...excludeTypes)', { excludeTypes: ps.excludeTypes }); | ||||
| 			if (includeTypes && includeTypes.length > 0) { | ||||
| 				query.andWhere('notification.type IN (:...includeTypes)', { includeTypes }); | ||||
| 			} else if (excludeTypes && excludeTypes.length > 0) { | ||||
| 				query.andWhere('notification.type NOT IN (:...excludeTypes)', { excludeTypes }); | ||||
| 			} | ||||
|  | ||||
| 			if (ps.unreadOnly) { | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| export const notificationTypes = ['follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'achievementEarned', 'app'] as const; | ||||
| export const notificationTypes = ['follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'achievementEarned', 'app'] as const; | ||||
| export const obsoleteNotificationTypes = ['pollVote', 'groupInvited'] as const; | ||||
|  | ||||
| export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
| 	:with-ok-button="true" | ||||
| 	:ok-button-disabled="false" | ||||
| 	@ok="ok()" | ||||
| 	@close="dialog.close()" | ||||
| 	@close="dialog?.close()" | ||||
| 	@closed="emit('closed')" | ||||
| > | ||||
| 	<template #header>{{ i18n.ts.notificationSetting }}</template> | ||||
| @@ -25,7 +25,7 @@ | ||||
| 					<MkButton inline @click="disableAll">{{ i18n.ts.disableAll }}</MkButton> | ||||
| 					<MkButton inline @click="enableAll">{{ i18n.ts.enableAll }}</MkButton> | ||||
| 				</div> | ||||
| 				<MkSwitch v-for="ntype in notificationTypes" :key="ntype" v-model="typesMap[ntype]">{{ i18n.t(`_notification._types.${ntype}`) }}</MkSwitch> | ||||
| 				<MkSwitch v-for="ntype in notificationTypes" :key="ntype" v-model="typesMap[ntype].value">{{ i18n.t(`_notification._types.${ntype}`) }}</MkSwitch> | ||||
| 			</template> | ||||
| 		</div> | ||||
| 	</MkSpacer> | ||||
| @@ -33,14 +33,16 @@ | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { } from 'vue'; | ||||
| import { notificationTypes } from 'misskey-js'; | ||||
| import { ref, Ref } from 'vue'; | ||||
| import MkSwitch from './MkSwitch.vue'; | ||||
| import MkInfo from './MkInfo.vue'; | ||||
| import MkButton from './MkButton.vue'; | ||||
| import MkModalWindow from '@/components/MkModalWindow.vue'; | ||||
| import { notificationTypes } from '@/const'; | ||||
| import { i18n } from '@/i18n'; | ||||
|  | ||||
| type TypesMap = Record<typeof notificationTypes[number], Ref<boolean>> | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'done', v: { includingTypes: string[] | null }): void, | ||||
| 	(ev: 'closed'): void, | ||||
| @@ -54,39 +56,35 @@ const props = withDefaults(defineProps<{ | ||||
| 	showGlobalToggle: true, | ||||
| }); | ||||
|  | ||||
| let includingTypes = $computed(() => props.includingTypes ?? []); | ||||
| let includingTypes = $computed(() => props.includingTypes?.filter(x => notificationTypes.includes(x)) ?? []); | ||||
|  | ||||
| const dialog = $shallowRef<InstanceType<typeof MkModalWindow>>(); | ||||
|  | ||||
| let typesMap = $ref<Record<typeof notificationTypes[number], boolean>>({}); | ||||
| const typesMap: TypesMap = notificationTypes.reduce((p, t) => ({ ...p, [t]: ref<boolean>(includingTypes.includes(t)) }), {} as any); | ||||
| let useGlobalSetting = $ref((includingTypes === null || includingTypes.length === 0) && props.showGlobalToggle); | ||||
|  | ||||
| for (const ntype of notificationTypes) { | ||||
| 	typesMap[ntype] = includingTypes.includes(ntype); | ||||
| } | ||||
|  | ||||
| function ok() { | ||||
| 	if (useGlobalSetting) { | ||||
| 		emit('done', { includingTypes: null }); | ||||
| 	} else { | ||||
| 		emit('done', { | ||||
| 			includingTypes: (Object.keys(typesMap) as typeof notificationTypes[number][]) | ||||
| 				.filter(type => typesMap[type]), | ||||
| 				.filter(type => typesMap[type].value), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	dialog.close(); | ||||
| 	if (dialog) dialog.close(); | ||||
| } | ||||
|  | ||||
| function disableAll() { | ||||
| 	for (const type in typesMap) { | ||||
| 		typesMap[type as typeof notificationTypes[number]] = false; | ||||
| 	for (const type of notificationTypes) { | ||||
| 		typesMap[type].value = false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| function enableAll() { | ||||
| 	for (const type in typesMap) { | ||||
| 		typesMap[type as typeof notificationTypes[number]] = true; | ||||
| 	for (const type of notificationTypes) { | ||||
| 		typesMap[type].value = true; | ||||
| 	} | ||||
| } | ||||
| </script> | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { onUnmounted, onMounted, computed, shallowRef } from 'vue'; | ||||
| import { notificationTypes } from 'misskey-js'; | ||||
| import MkPagination, { Paging } from '@/components/MkPagination.vue'; | ||||
| import XNotification from '@/components/MkNotification.vue'; | ||||
| import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue'; | ||||
| @@ -26,6 +25,7 @@ import XNote from '@/components/MkNote.vue'; | ||||
| import { stream } from '@/stream'; | ||||
| import { $i } from '@/account'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { notificationTypes } from '@/const'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	includeTypes?: typeof notificationTypes[number][]; | ||||
|   | ||||
| @@ -43,3 +43,6 @@ https://github.com/sindresorhus/file-type/blob/main/supported.js | ||||
| https://github.com/sindresorhus/file-type/blob/main/core.js | ||||
| https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers | ||||
| */ | ||||
|  | ||||
| export const notificationTypes = ['follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'achievementEarned', 'app'] as const; | ||||
| export const obsoleteNotificationTypes = ['pollVote', 'groupInvited'] as const; | ||||
|   | ||||
| @@ -17,12 +17,12 @@ | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { computed } from 'vue'; | ||||
| import { notificationTypes } from 'misskey-js'; | ||||
| import XNotifications from '@/components/MkNotifications.vue'; | ||||
| import MkNotes from '@/components/MkNotes.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | ||||
| import { notificationTypes } from '@/const'; | ||||
|  | ||||
| let tab = $ref('all'); | ||||
| let includeTypes = $ref<string[] | null>(null); | ||||
|   | ||||
| @@ -27,7 +27,6 @@ | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { defineAsyncComponent } from 'vue'; | ||||
| import { notificationTypes } from 'misskey-js'; | ||||
| import FormLink from '@/components/form/link.vue'; | ||||
| import FormSection from '@/components/form/section.vue'; | ||||
| import MkSwitch from '@/components/MkSwitch.vue'; | ||||
| @@ -36,6 +35,7 @@ import { $i } from '@/account'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | ||||
| import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue'; | ||||
| import { notificationTypes } from '@/const'; | ||||
|  | ||||
| let allowButton = $shallowRef<InstanceType<typeof MkPushNotificationAllowButton>>(); | ||||
| let pushRegistrationInServer = $computed(() => allowButton?.pushRegistrationInServer); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 tamaina
					tamaina