diff --git a/CHANGELOG.md b/CHANGELOG.md
index 513338e66..010d5aed7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
### General
- Enhance: サーバーごとにモデレーションノートを残せるように
- Enhance: コンディショナルロールの条件に「マニュアルロールへのアサイン」を追加
+- Enhance: 通知の受信設定に「フォロー中またはフォロワー」を追加
### Client
- Enhance: ノート作成画面のファイル添付メニューの区切り線の位置を調整
@@ -33,6 +34,7 @@
- 必須パラメータを`id`または`name`のいずれかのみに
- `id`の代わりに`name`で絵文字を指定可能に(`id`・`name`両指定時は従来通り`name`を変更する挙動)
- `category`および`licence`が指定なしの時勝手にnullに上書きされる挙動を修正
+- Fix: 通知の受信設定で「相互フォロー」が正しく動作しない問題を修正
## 2024.2.0
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 7d5f8ce73..3edc9d235 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4656,6 +4656,10 @@ export interface Locale extends ILocale {
* 相互フォロー
*/
"mutualFollow": string;
+ /**
+ * フォロー中またはフォロワー
+ */
+ "followingOrFollower": string;
/**
* ファイル付きのみ
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 1bb56738c..66ddf6a46 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1160,6 +1160,7 @@ showRenotes: "リノートを表示"
edited: "編集済み"
notificationRecieveConfig: "通知の受信設定"
mutualFollow: "相互フォロー"
+followingOrFollower: "フォロー中またはフォロワー"
fileAttachedOnly: "ファイル付きのみ"
showRepliesToOthersInTimeline: "TLに他の人への返信を含める"
hideRepliesToOthersInTimeline: "TLに他の人への返信を含めない"
diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts
index ee1619357..722434199 100644
--- a/packages/backend/src/core/NotificationService.ts
+++ b/packages/backend/src/core/NotificationService.ts
@@ -122,6 +122,14 @@ export class NotificationService implements OnApplicationShutdown {
return null;
}
} else if (recieveConfig?.type === 'mutualFollow') {
+ const [isFollowing, isFollower] = await Promise.all([
+ this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)),
+ this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)),
+ ]);
+ if (!(isFollowing && isFollower)) {
+ return null;
+ }
+ } else if (recieveConfig?.type === 'followingOrFollower') {
const [isFollowing, isFollower] = await Promise.all([
this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)),
this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)),
diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts
index 1ca2f5585..7dbe0b371 100644
--- a/packages/backend/src/models/UserProfile.ts
+++ b/packages/backend/src/models/UserProfile.ts
@@ -249,6 +249,8 @@ export class MiUserProfile {
type: 'follower';
} | {
type: 'mutualFollow';
+ } | {
+ type: 'followingOrFollower';
} | {
type: 'list';
userListId: MiUserList['id'];
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index 952cd6bf8..947a9317d 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -13,7 +13,7 @@ export const notificationRecieveConfig = {
type: {
type: 'string',
nullable: false,
- enum: ['all', 'following', 'follower', 'mutualFollow', 'never'],
+ enum: ['all', 'following', 'follower', 'mutualFollow', 'followingOrFollower', 'never'],
},
},
required: ['type'],
diff --git a/packages/frontend/src/pages/settings/notifications.notification-config.vue b/packages/frontend/src/pages/settings/notifications.notification-config.vue
index d6aac6367..a36f03630 100644
--- a/packages/frontend/src/pages/settings/notifications.notification-config.vue
+++ b/packages/frontend/src/pages/settings/notifications.notification-config.vue
@@ -10,6 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue
index febcfa32e..bbcef6528 100644
--- a/packages/frontend/src/pages/settings/notifications.vue
+++ b/packages/frontend/src/pages/settings/notifications.vue
@@ -16,6 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
$i.notificationRecieveConfig[type]?.type === 'following' ? i18n.ts.following :
$i.notificationRecieveConfig[type]?.type === 'follower' ? i18n.ts.followers :
$i.notificationRecieveConfig[type]?.type === 'mutualFollow' ? i18n.ts.mutualFollow :
+ $i.notificationRecieveConfig[type]?.type === 'followingOrFollower' ? i18n.ts.followingOrFollower :
$i.notificationRecieveConfig[type]?.type === 'list' ? i18n.ts.userList :
i18n.ts.all
}}
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 8d700fb82..a3597e463 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -3700,7 +3700,7 @@ export type components = {
notificationRecieveConfig: {
note?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3709,7 +3709,7 @@ export type components = {
}]>;
follow?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3718,7 +3718,7 @@ export type components = {
}]>;
mention?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3727,7 +3727,7 @@ export type components = {
}]>;
reply?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3736,7 +3736,7 @@ export type components = {
}]>;
renote?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3745,7 +3745,7 @@ export type components = {
}]>;
quote?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3754,7 +3754,7 @@ export type components = {
}]>;
reaction?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3763,7 +3763,7 @@ export type components = {
}]>;
pollEnded?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3772,7 +3772,7 @@ export type components = {
}]>;
receiveFollowRequest?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3781,7 +3781,7 @@ export type components = {
}]>;
followRequestAccepted?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3790,7 +3790,7 @@ export type components = {
}]>;
roleAssigned?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3799,7 +3799,7 @@ export type components = {
}]>;
achievementEarned?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3808,7 +3808,7 @@ export type components = {
}]>;
app?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -3817,7 +3817,7 @@ export type components = {
}]>;
test?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8436,7 +8436,7 @@ export type operations = {
notificationRecieveConfig: {
note?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8445,7 +8445,7 @@ export type operations = {
}]>;
follow?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8454,7 +8454,7 @@ export type operations = {
}]>;
mention?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8463,7 +8463,7 @@ export type operations = {
}]>;
reply?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8472,7 +8472,7 @@ export type operations = {
}]>;
renote?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8481,7 +8481,7 @@ export type operations = {
}]>;
quote?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8490,7 +8490,7 @@ export type operations = {
}]>;
reaction?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8499,7 +8499,7 @@ export type operations = {
}]>;
pollEnded?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8508,7 +8508,7 @@ export type operations = {
}]>;
receiveFollowRequest?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8517,7 +8517,7 @@ export type operations = {
}]>;
followRequestAccepted?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8526,7 +8526,7 @@ export type operations = {
}]>;
roleAssigned?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8535,7 +8535,7 @@ export type operations = {
}]>;
achievementEarned?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8544,7 +8544,7 @@ export type operations = {
}]>;
app?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -8553,7 +8553,7 @@ export type operations = {
}]>;
test?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18787,7 +18787,7 @@ export type operations = {
notificationRecieveConfig?: {
note?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18796,7 +18796,7 @@ export type operations = {
}]>;
follow?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18805,7 +18805,7 @@ export type operations = {
}]>;
mention?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18814,7 +18814,7 @@ export type operations = {
}]>;
reply?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18823,7 +18823,7 @@ export type operations = {
}]>;
renote?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18832,7 +18832,7 @@ export type operations = {
}]>;
quote?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18841,7 +18841,7 @@ export type operations = {
}]>;
reaction?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18850,7 +18850,7 @@ export type operations = {
}]>;
pollEnded?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18859,7 +18859,7 @@ export type operations = {
}]>;
receiveFollowRequest?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18868,7 +18868,7 @@ export type operations = {
}]>;
followRequestAccepted?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18877,7 +18877,7 @@ export type operations = {
}]>;
roleAssigned?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18886,7 +18886,7 @@ export type operations = {
}]>;
achievementEarned?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18895,7 +18895,7 @@ export type operations = {
}]>;
app?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';
@@ -18904,7 +18904,7 @@ export type operations = {
}]>;
test?: OneOf<[{
/** @enum {string} */
- type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'never';
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
}, {
/** @enum {string} */
type: 'list';