From 9f5ab14d7063532de2b049bc2ed40a15658168f5 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 13:22:42 +0900 Subject: [PATCH 01/26] feat: add defaultWithReplies to MiUser --- .../1697430068149-DefaultWithReplies.js | 18 ++++++++++++++++++ packages/backend/src/models/User.ts | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 packages/backend/migration/1697430068149-DefaultWithReplies.js diff --git a/packages/backend/migration/1697430068149-DefaultWithReplies.js b/packages/backend/migration/1697430068149-DefaultWithReplies.js new file mode 100644 index 000000000000..e93e55a93b5b --- /dev/null +++ b/packages/backend/migration/1697430068149-DefaultWithReplies.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class DefaultWithReplies1697430068149 { + name = 'DefaultWithReplies1697430068149' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "defaultWithReplies" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`COMMENT ON COLUMN "user"."defaultWithReplies" IS 'Default value of withReplies for newly followed users'`); + } + + async down(queryRunner) { + await queryRunner.query(`COMMENT ON COLUMN "user"."defaultWithReplies" IS 'Default value of withReplies for newly followed users'`); + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "defaultWithReplies"`); + } +} diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 796d7c8356d7..a767302265ed 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -243,6 +243,12 @@ export class MiUser { }) public token: string | null; + @Column('boolean', { + default: false, + comment: 'Default value of withReplies for newly followed users', + }) + public defaultWithReplies: boolean; + constructor(data: Partial) { if (data == null) return; From 846994ba76cca18c87f6261bef1fc696e63ea64a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 13:31:08 +0900 Subject: [PATCH 02/26] feat: use defaultWithReplies when creating MiFollowing --- packages/backend/src/core/UserFollowingService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index f6d0c3a6d5ee..c2cbdefaf2b9 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -187,7 +187,7 @@ export class UserFollowingService implements OnModuleInit { id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'] }, follower: { - id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'] + id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'], defaultWithReplies: MiUser['defaultWithReplies']; }, silent = false, ): Promise { @@ -199,6 +199,7 @@ export class UserFollowingService implements OnModuleInit { id: this.idService.gen(), followerId: follower.id, followeeId: followee.id, + withReplies: follower.defaultWithReplies, // 非正規化 followerHost: follower.host, From 95e3cee6b056ea46ca0ffba2fa363a896055068d Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 13:36:43 +0900 Subject: [PATCH 03/26] feat: update defaultWithReplies from API --- packages/backend/src/server/api/endpoints/i/update.ts | 2 ++ packages/misskey-js/etc/misskey-js.api.md | 3 ++- packages/misskey-js/src/api.types.ts | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 431bb4c60a7e..309896840b9f 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -159,6 +159,7 @@ export const paramDef = { receiveAnnouncementEmail: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' }, autoSensitive: { type: 'boolean' }, + defaultWithReplies: { type: 'boolean' }, ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true }, mutedWords: { type: 'array' }, @@ -264,6 +265,7 @@ export default class extends Endpoint { // eslint- profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw; } if (typeof ps.autoSensitive === 'boolean') profileUpdates.autoSensitive = ps.autoSensitive; + if (typeof ps.defaultWithReplies === 'boolean') updates.defaultWithReplies = ps.defaultWithReplies; if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; if (ps.avatarId) { diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 1a0bbeac78ea..9bacecd615bb 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1540,6 +1540,7 @@ export type Endpoints = { injectFeaturedNote?: boolean; receiveAnnouncementEmail?: boolean; alwaysMarkNsfw?: boolean; + defaultWithReplies?: boolean; mutedWords?: string[][]; notificationRecieveConfig?: any; emailNotificationTypes?: string[]; @@ -2982,7 +2983,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:631:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:600:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index a7a2ea1b36ee..faf70eb08f60 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -428,6 +428,7 @@ export type Endpoints = { injectFeaturedNote?: boolean; receiveAnnouncementEmail?: boolean; alwaysMarkNsfw?: boolean; + defaultWithReplies?: boolean; mutedWords?: string[][]; notificationRecieveConfig?: any; emailNotificationTypes?: string[]; From f2cc4fe693ed5b31bfdf7cfaa9b0b24bb2cd850e Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 14:40:27 +0900 Subject: [PATCH 04/26] feat: return defaultWithReplies as a part of $i --- packages/backend/src/core/entities/UserEntityService.ts | 1 + packages/backend/src/models/json-schema/user.ts | 3 +++ packages/misskey-js/etc/misskey-js.api.md | 3 ++- packages/misskey-js/src/entities.ts | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 212994feef2b..3bdea9c118dc 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -445,6 +445,7 @@ export class UserEntityService implements OnModuleInit { mutingNotificationTypes: [], // 後方互換性のため notificationRecieveConfig: profile!.notificationRecieveConfig, emailNotificationTypes: profile!.emailNotificationTypes, + defaultWithReplies: user!.defaultWithReplies, achievements: profile!.achievements, loggedInDays: profile!.loggedInDates.length, policies: this.roleService.getUserPolicies(user.id), diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 57d2d976ff7a..881a50e0cb35 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -403,6 +403,9 @@ export const packedMeDetailedOnlySchema = { nullable: false, optional: false, }, }, + defaultWithReplies: { + type: 'boolean', + }, //#region secrets email: { type: 'string', diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 9bacecd615bb..8b163e670063 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2494,6 +2494,7 @@ type MeDetailed = UserDetailed & { noCrawle: boolean; receiveAnnouncementEmail: boolean; usePasswordLessLogin: boolean; + defaultWithReplies: boolean; unreadAnnouncements: Announcement[]; twoFactorBackupCodesStock: 'full' | 'partial' | 'none'; [other: string]: any; @@ -2985,7 +2986,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts // src/api.types.ts:631:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts -// src/entities.ts:600:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// src/entities.ts:601:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index aed242d8aa8b..8060598c0513 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -123,6 +123,7 @@ export type MeDetailed = UserDetailed & { noCrawle: boolean; receiveAnnouncementEmail: boolean; usePasswordLessLogin: boolean; + defaultWithReplies: boolean; unreadAnnouncements: Announcement[]; twoFactorBackupCodesStock: 'full' | 'partial' | 'none'; [other: string]: any; From 1b571c8c13bb59a9c8219e95746b514690fc59d8 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 14:42:26 +0900 Subject: [PATCH 05/26] feat(frontend): configure defaultWithReplies --- locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + packages/frontend/src/pages/settings/general.vue | 9 +++++++++ 3 files changed, 11 insertions(+) diff --git a/locales/index.d.ts b/locales/index.d.ts index 2494c1709b3f..46514ed20024 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -534,6 +534,7 @@ export interface Locale { "deleteAll": string; "showFixedPostForm": string; "showFixedPostFormInChannel": string; + "withRepliesByDefaultForNewlyFollowed": string; "newNoteRecived": string; "sounds": string; "sound": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9adc4381a716..9a2b911acc5b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -531,6 +531,7 @@ serverLogs: "サーバーログ" deleteAll: "全て削除" showFixedPostForm: "タイムライン上部に投稿フォームを表示する" showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)" +withRepliesByDefaultForNewlyFollowed: "あらたににフォローした人のリプライをTLに追加するようにする" newNoteRecived: "新しいノートがあります" sounds: "サウンド" sound: "サウンド" diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 55de53fb0785..9c3dfc2ed91a 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -29,6 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.showFixedPostForm }} {{ i18n.ts.showFixedPostFormInChannel }} + {{ i18n.ts.withRepliesByDefaultForNewlyFollowed }} @@ -202,6 +203,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import { miLocalStorage } from '@/local-storage.js'; import { globalEvents } from '@/events'; import { claimAchievement } from '@/scripts/achievements.js'; +import {$i} from "@/account.js"; const lang = ref(miLocalStorage.getItem('lang')); const fontSize = ref(miLocalStorage.getItem('fontSize')); @@ -249,6 +251,7 @@ const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter(' const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); const keepScreenOn = computed(defaultStore.makeGetterSetter('keepScreenOn')); +const defaultWithReplies = ref($i!.defaultWithReplies); // TODO watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); @@ -289,6 +292,12 @@ watch([ await reloadAsk(); }); +watch([defaultWithReplies], async () => { + os.api('i/update', { + defaultWithReplies: defaultWithReplies.value, + }); +}); + const emojiIndexLangs = ['en-US']; function downloadEmojiIndex(lang: string) { From 758c46e64e0cd4f6b8c4e87e1ebb46350b3ac368 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 14:47:24 +0900 Subject: [PATCH 06/26] =?UTF-8?q?docs(changelog):=20=E6=96=B0=E8=A6=8F?= =?UTF-8?q?=E3=81=AB=E3=83=95=E3=82=A9=E3=83=AD=E3=83=BC=E3=81=97=E3=81=9F?= =?UTF-8?q?=E4=BA=BA=E3=81=AE=E3=82=92=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB?= =?UTF-8?q?=E3=83=88=E3=81=A7TL=E4=BA=8C=E8=BF=BD=E5=8A=A0=E3=81=A7?= =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85a998de101d..61885b631722 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ ## 2023.x.x (unreleased) ### General -- +- Enhance: 新規にフォローした人のをデフォルトでTL二追加できるように ### Client - Enhance: TLの返信表示オプションを記憶するように From 7351c8432d097239c110806404c274771c96b78f Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+sayamame-beans@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:21:02 +0900 Subject: [PATCH 07/26] fix: typo --- locales/ja-JP.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9a2b911acc5b..c96daae44c92 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -531,7 +531,7 @@ serverLogs: "サーバーログ" deleteAll: "全て削除" showFixedPostForm: "タイムライン上部に投稿フォームを表示する" showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)" -withRepliesByDefaultForNewlyFollowed: "あらたににフォローした人のリプライをTLに追加するようにする" +withRepliesByDefaultForNewlyFollowed: "あらたにフォローした人のリプライをTLに追加するようにする" newNoteRecived: "新しいノートがあります" sounds: "サウンド" sound: "サウンド" From 680517f858317cdac8ed5d59731983453c628f1c Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 15:37:29 +0900 Subject: [PATCH 08/26] style: fix lint failure --- packages/frontend/src/pages/settings/general.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 9c3dfc2ed91a..36988fff83c5 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -203,7 +203,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import { miLocalStorage } from '@/local-storage.js'; import { globalEvents } from '@/events'; import { claimAchievement } from '@/scripts/achievements.js'; -import {$i} from "@/account.js"; +import { $i } from "@/account.js"; const lang = ref(miLocalStorage.getItem('lang')); const fontSize = ref(miLocalStorage.getItem('fontSize')); From 3bccba571b86b8c96784fc1ed02c569616dcfbe6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 16 Oct 2023 16:13:44 +0900 Subject: [PATCH 09/26] chore: improve UI text --- locales/ja-JP.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index c96daae44c92..fad5612b62d3 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -531,7 +531,7 @@ serverLogs: "サーバーログ" deleteAll: "全て削除" showFixedPostForm: "タイムライン上部に投稿フォームを表示する" showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)" -withRepliesByDefaultForNewlyFollowed: "あらたにフォローした人のリプライをTLに追加するようにする" +withRepliesByDefaultForNewlyFollowed: "フォローする際、デフォルトで返信をTLに含むようにする" newNoteRecived: "新しいノートがあります" sounds: "サウンド" sound: "サウンド" From 8e3e5aef281fcfba7a2edb73f5d6ba0fec3318dc Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:19:39 +0900 Subject: [PATCH 10/26] chore: make optional params of UserFollowingService.follow() object --- packages/backend/src/core/UserFollowingService.ts | 9 ++++++++- packages/backend/src/core/activitypub/ApInboxService.ts | 2 +- .../src/queue/processors/RelationshipProcessorService.ts | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index c2cbdefaf2b9..e9a7d560e450 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -91,7 +91,14 @@ export class UserFollowingService implements OnModuleInit { } @bindThis - public async follow(_follower: { id: MiUser['id'] }, _followee: { id: MiUser['id'] }, requestId?: string, silent = false): Promise { + public async follow( + _follower: { id: MiUser['id'] }, + _followee: { id: MiUser['id'] }, + { requestId, silent = false }: { + requestId?: string, + silent?: boolean, + } = {}, + ): Promise { const [follower, followee] = await Promise.all([ this.usersRepository.findOneByOrFail({ id: _follower.id }), this.usersRepository.findOneByOrFail({ id: _followee.id }), diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 8d5d34d40b0a..7aba14068951 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -164,7 +164,7 @@ export class ApInboxService { } // don't queue because the sender may attempt again when timeout - await this.userFollowingService.follow(actor, followee, activity.id); + await this.userFollowingService.follow(actor, followee, { requestId: activity.id }); return 'ok'; } diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index 5b2d2ef3139f..ec6c55d11e2d 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -35,7 +35,10 @@ export class RelationshipProcessorService { @bindThis public async processFollow(job: Bull.Job): Promise { this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id}`); - await this.userFollowingService.follow(job.data.from, job.data.to, job.data.requestId, job.data.silent); + await this.userFollowingService.follow(job.data.from, job.data.to, { + requestId: job.data.requestId, + silent: job.data.silent + }); return 'ok'; } From c18373696783889e000ae7a19bf571fa156aab79 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:25:47 +0900 Subject: [PATCH 11/26] chore: UserFollowingService.follow() accept withReplies --- packages/backend/src/core/UserFollowingService.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index e9a7d560e450..6ea2f0296bf5 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -94,9 +94,10 @@ export class UserFollowingService implements OnModuleInit { public async follow( _follower: { id: MiUser['id'] }, _followee: { id: MiUser['id'] }, - { requestId, silent = false }: { + { requestId, silent = false, withReplies }: { requestId?: string, silent?: boolean, + withReplies?: boolean, } = {}, ): Promise { const [follower, followee] = await Promise.all([ @@ -175,12 +176,13 @@ export class UserFollowingService implements OnModuleInit { } if (!autoAccept) { + // TODO: withReplies await this.createFollowRequest(follower, followee, requestId); return; } } - await this.insertFollowingDoc(followee, follower, silent); + await this.insertFollowingDoc(followee, follower, silent, withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee)); @@ -194,9 +196,10 @@ export class UserFollowingService implements OnModuleInit { id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'] }, follower: { - id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'], defaultWithReplies: MiUser['defaultWithReplies']; + id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'] }, silent = false, + withReplies?: boolean, ): Promise { if (follower.id === followee.id) return; @@ -206,7 +209,7 @@ export class UserFollowingService implements OnModuleInit { id: this.idService.gen(), followerId: follower.id, followeeId: followee.id, - withReplies: follower.defaultWithReplies, + withReplies: withReplies, // 非正規化 followerHost: follower.host, From e289eec220ad7db99e1629704a2c806b1bb13d67 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:33:06 +0900 Subject: [PATCH 12/26] chore: add withReplies to MiFollowRequest --- .../1697441463087-FollowRequestWithReplies.js | 17 +++++++++++++++++ packages/backend/src/models/FollowRequest.ts | 5 +++++ 2 files changed, 22 insertions(+) create mode 100644 packages/backend/migration/1697441463087-FollowRequestWithReplies.js diff --git a/packages/backend/migration/1697441463087-FollowRequestWithReplies.js b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js new file mode 100644 index 000000000000..214c6f6680cf --- /dev/null +++ b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + + +export class FollowRequestWithReplies1697441463087 { + name = 'FollowRequestWithReplies1697441463087' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "follow_request" ADD "withReplies" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "follow_request" DROP COLUMN "withReplies"`); + } +} diff --git a/packages/backend/src/models/FollowRequest.ts b/packages/backend/src/models/FollowRequest.ts index 1e907f3d68ef..9899694dd61d 100644 --- a/packages/backend/src/models/FollowRequest.ts +++ b/packages/backend/src/models/FollowRequest.ts @@ -45,6 +45,11 @@ export class MiFollowRequest { }) public requestId: string | null; + @Column('boolean', { + default: false, + }) + public withReplies: boolean; + //#region Denormalized fields @Column('varchar', { length: 128, nullable: true, From 6e2b43213a3c0798dd06191fc939abf872cfd042 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:35:47 +0900 Subject: [PATCH 13/26] chore: process withReplies for follow request --- packages/backend/src/core/UserFollowingService.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 6ea2f0296bf5..c46c0d724b2e 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -176,8 +176,7 @@ export class UserFollowingService implements OnModuleInit { } if (!autoAccept) { - // TODO: withReplies - await this.createFollowRequest(follower, followee, requestId); + await this.createFollowRequest(follower, followee, requestId, withReplies); return; } } @@ -462,6 +461,7 @@ export class UserFollowingService implements OnModuleInit { id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']; }, requestId?: string, + withReplies?: boolean, ): Promise { if (follower.id === followee.id) return; @@ -479,6 +479,7 @@ export class UserFollowingService implements OnModuleInit { followerId: follower.id, followeeId: followee.id, requestId, + withReplies, // 非正規化 followerHost: follower.host, @@ -563,7 +564,7 @@ export class UserFollowingService implements OnModuleInit { throw new IdentifiableError('8884c2dd-5795-4ac9-b27e-6a01d38190f9', 'No follow request.'); } - await this.insertFollowingDoc(followee, follower); + await this.insertFollowingDoc(followee, follower, false, request.withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as MiPartialLocalUser, request.requestId!), followee)); From 0a2befa0223b37770f9094a5f4c2b9532dfef44a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:37:54 +0900 Subject: [PATCH 14/26] feat: accept withReplies on 'following/create' endpoint --- .../backend/src/server/api/endpoints/following/create.ts | 3 ++- packages/misskey-js/etc/misskey-js.api.md | 3 ++- packages/misskey-js/src/api.types.ts | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index e0e7fed87a23..bb55b2c4ec0f 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -71,6 +71,7 @@ export const paramDef = { type: 'object', properties: { userId: { type: 'string', format: 'misskey:id' }, + withReplies: { type: 'boolean' } }, required: ['userId'], } as const; @@ -112,7 +113,7 @@ export default class extends Endpoint { // eslint- } try { - await this.userFollowingService.follow(follower, followee); + await this.userFollowingService.follow(follower, followee, {}); } catch (e) { if (e instanceof IdentifiableError) { if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 6443a01e84de..261fdaedd4ba 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1184,6 +1184,7 @@ export type Endpoints = { 'following/create': { req: { userId: User['id']; + withReplies?: boolean; }; res: User; }; @@ -2985,7 +2986,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:631:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:634:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:602:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index faf70eb08f60..4e6c70f11400 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -321,7 +321,10 @@ export type Endpoints = { 'federation/users': { req: { host: string; limit?: number; sinceId?: User['id']; untilId?: User['id']; }; res: UserDetailed[]; }; // following - 'following/create': { req: { userId: User['id'] }; res: User; }; + 'following/create': { req: { + userId: User['id'], + withReplies?: boolean, + }; res: User; }; 'following/delete': { req: { userId: User['id'] }; res: User; }; 'following/requests/accept': { req: { userId: User['id'] }; res: null; }; 'following/requests/cancel': { req: { userId: User['id'] }; res: User; }; From aa39b776166395ba01a86a3972b78a7d97ab29ad Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:43:50 +0900 Subject: [PATCH 15/26] feat: store defaultWithReplies in client store --- packages/frontend/src/components/MkFollowButton.vue | 2 ++ packages/frontend/src/pages/follow.vue | 2 ++ packages/frontend/src/pages/settings/general.vue | 9 +-------- packages/frontend/src/store.ts | 4 ++++ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index 15043fcd0b86..cd8c88f23a73 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -42,6 +42,7 @@ import { useStream } from '@/stream.js'; import { i18n } from '@/i18n.js'; import { claimAchievement } from '@/scripts/achievements.js'; import { $i } from '@/account.js'; +import { defaultStore } from "@/store.js"; const props = withDefaults(defineProps<{ user: Misskey.entities.UserDetailed, @@ -95,6 +96,7 @@ async function onClick() { } else { await os.api('following/create', { userId: props.user.id, + withReplies: defaultStore.state.defaultWithReplies, }); hasPendingFollowRequestFromYou = true; diff --git a/packages/frontend/src/pages/follow.vue b/packages/frontend/src/pages/follow.vue index e382cabd7480..482071e9b41d 100644 --- a/packages/frontend/src/pages/follow.vue +++ b/packages/frontend/src/pages/follow.vue @@ -14,6 +14,7 @@ import * as Misskey from 'misskey-js'; import * as os from '@/os.js'; import { mainRouter } from '@/router.js'; import { i18n } from '@/i18n.js'; +import { defaultStore } from "@/store.js"; async function follow(user): Promise { const { canceled } = await os.confirm({ @@ -28,6 +29,7 @@ async function follow(user): Promise { os.apiWithDialog('following/create', { userId: user.id, + withReplies: defaultStore.state.defaultWithReplies, }); } diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 36988fff83c5..30443fded6c0 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -203,7 +203,6 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import { miLocalStorage } from '@/local-storage.js'; import { globalEvents } from '@/events'; import { claimAchievement } from '@/scripts/achievements.js'; -import { $i } from "@/account.js"; const lang = ref(miLocalStorage.getItem('lang')); const fontSize = ref(miLocalStorage.getItem('fontSize')); @@ -251,7 +250,7 @@ const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter(' const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); const keepScreenOn = computed(defaultStore.makeGetterSetter('keepScreenOn')); -const defaultWithReplies = ref($i!.defaultWithReplies); // TODO +const defaultWithReplies = computed(defaultStore.makeGetterSetter('defaultWithReplies')); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); @@ -292,12 +291,6 @@ watch([ await reloadAsk(); }); -watch([defaultWithReplies], async () => { - os.api('i/update', { - defaultWithReplies: defaultWithReplies.value, - }); -}); - const emojiIndexLangs = ['en-US']; function downloadEmojiIndex(lang: string) { diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 2829411ae585..92d01e4caf13 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -361,6 +361,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, + defaultWithReplies: { + where: 'account', + default: false, + }, })); // TODO: 他のタブと永続化されたstateを同期 From 03b20049931b0f5ef6384f36ef8fe85c8b41f93a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:44:49 +0900 Subject: [PATCH 16/26] Revert "feat: return defaultWithReplies as a part of $i" This reverts commit f2cc4fe6 --- packages/backend/src/core/entities/UserEntityService.ts | 1 - packages/backend/src/models/json-schema/user.ts | 3 --- packages/misskey-js/etc/misskey-js.api.md | 3 +-- packages/misskey-js/src/entities.ts | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 3bdea9c118dc..212994feef2b 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -445,7 +445,6 @@ export class UserEntityService implements OnModuleInit { mutingNotificationTypes: [], // 後方互換性のため notificationRecieveConfig: profile!.notificationRecieveConfig, emailNotificationTypes: profile!.emailNotificationTypes, - defaultWithReplies: user!.defaultWithReplies, achievements: profile!.achievements, loggedInDays: profile!.loggedInDates.length, policies: this.roleService.getUserPolicies(user.id), diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 881a50e0cb35..57d2d976ff7a 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -403,9 +403,6 @@ export const packedMeDetailedOnlySchema = { nullable: false, optional: false, }, }, - defaultWithReplies: { - type: 'boolean', - }, //#region secrets email: { type: 'string', diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 261fdaedd4ba..70bbad3754e1 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2496,7 +2496,6 @@ type MeDetailed = UserDetailed & { noCrawle: boolean; receiveAnnouncementEmail: boolean; usePasswordLessLogin: boolean; - defaultWithReplies: boolean; unreadAnnouncements: Announcement[]; twoFactorBackupCodesStock: 'full' | 'partial' | 'none'; [other: string]: any; @@ -2988,7 +2987,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts // src/api.types.ts:634:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts -// src/entities.ts:602:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// src/entities.ts:601:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 489845194fd4..bcf553853220 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -123,7 +123,6 @@ export type MeDetailed = UserDetailed & { noCrawle: boolean; receiveAnnouncementEmail: boolean; usePasswordLessLogin: boolean; - defaultWithReplies: boolean; unreadAnnouncements: Announcement[]; twoFactorBackupCodesStock: 'full' | 'partial' | 'none'; [other: string]: any; From 7eac6567e700a79bb636997bba8725dbe2c7ace9 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:45:51 +0900 Subject: [PATCH 17/26] Revert "feat: update defaultWithReplies from API" This reverts commit 95e3cee6 --- packages/backend/src/server/api/endpoints/i/update.ts | 2 -- packages/misskey-js/etc/misskey-js.api.md | 3 +-- packages/misskey-js/src/api.types.ts | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 309896840b9f..431bb4c60a7e 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -159,7 +159,6 @@ export const paramDef = { receiveAnnouncementEmail: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' }, autoSensitive: { type: 'boolean' }, - defaultWithReplies: { type: 'boolean' }, ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true }, mutedWords: { type: 'array' }, @@ -265,7 +264,6 @@ export default class extends Endpoint { // eslint- profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw; } if (typeof ps.autoSensitive === 'boolean') profileUpdates.autoSensitive = ps.autoSensitive; - if (typeof ps.defaultWithReplies === 'boolean') updates.defaultWithReplies = ps.defaultWithReplies; if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; if (ps.avatarId) { diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 70bbad3754e1..ad4403067b77 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1542,7 +1542,6 @@ export type Endpoints = { injectFeaturedNote?: boolean; receiveAnnouncementEmail?: boolean; alwaysMarkNsfw?: boolean; - defaultWithReplies?: boolean; mutedWords?: string[][]; notificationRecieveConfig?: any; emailNotificationTypes?: string[]; @@ -2985,7 +2984,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:634:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:601:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index 4e6c70f11400..8c6205bf5128 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -431,7 +431,6 @@ export type Endpoints = { injectFeaturedNote?: boolean; receiveAnnouncementEmail?: boolean; alwaysMarkNsfw?: boolean; - defaultWithReplies?: boolean; mutedWords?: string[][]; notificationRecieveConfig?: any; emailNotificationTypes?: string[]; From 2002af64b6a4be29612239137e15ee891a0da4d9 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 16:49:55 +0900 Subject: [PATCH 18/26] Revert "feat: add defaultWithReplies to MiUser" This reverts commit 9f5ab14d7063532de2b049bc2ed40a15658168f5. --- .../1697430068149-DefaultWithReplies.js | 18 ------------------ packages/backend/src/models/User.ts | 6 ------ 2 files changed, 24 deletions(-) delete mode 100644 packages/backend/migration/1697430068149-DefaultWithReplies.js diff --git a/packages/backend/migration/1697430068149-DefaultWithReplies.js b/packages/backend/migration/1697430068149-DefaultWithReplies.js deleted file mode 100644 index e93e55a93b5b..000000000000 --- a/packages/backend/migration/1697430068149-DefaultWithReplies.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and other misskey contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export class DefaultWithReplies1697430068149 { - name = 'DefaultWithReplies1697430068149' - - async up(queryRunner) { - await queryRunner.query(`ALTER TABLE "user" ADD "defaultWithReplies" boolean NOT NULL DEFAULT false`); - await queryRunner.query(`COMMENT ON COLUMN "user"."defaultWithReplies" IS 'Default value of withReplies for newly followed users'`); - } - - async down(queryRunner) { - await queryRunner.query(`COMMENT ON COLUMN "user"."defaultWithReplies" IS 'Default value of withReplies for newly followed users'`); - await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "defaultWithReplies"`); - } -} diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index a767302265ed..796d7c8356d7 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -243,12 +243,6 @@ export class MiUser { }) public token: string | null; - @Column('boolean', { - default: false, - comment: 'Default value of withReplies for newly followed users', - }) - public defaultWithReplies: boolean; - constructor(data: Partial) { if (data == null) return; From d436f8e11cecee818157ec7d644268000752f0b4 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 17:14:07 +0900 Subject: [PATCH 19/26] feat: configuring withReplies in import-following --- packages/backend/src/core/QueueService.ts | 9 +++++---- .../queue/processors/ImportFollowingProcessorService.ts | 4 ++-- .../src/queue/processors/RelationshipProcessorService.ts | 3 ++- packages/backend/src/queue/types.ts | 3 +++ .../src/server/api/endpoints/i/import-following.ts | 3 ++- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index d8c725003496..55b24f0ad2f7 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -237,10 +237,11 @@ export class QueueService { } @bindThis - public createImportFollowingJob(user: ThinUser, fileId: MiDriveFile['id']) { + public createImportFollowingJob(user: ThinUser, fileId: MiDriveFile['id'], withReplies?: boolean) { return this.dbQueue.add('importFollowing', { user: { id: user.id }, fileId: fileId, + withReplies, }, { removeOnComplete: true, removeOnFail: true, @@ -248,8 +249,8 @@ export class QueueService { } @bindThis - public createImportFollowingToDbJob(user: ThinUser, targets: string[]) { - const jobs = targets.map(rel => this.generateToDbJobData('importFollowingToDb', { user, target: rel })); + public createImportFollowingToDbJob(user: ThinUser, targets: string[], withReplies?: boolean) { + const jobs = targets.map(rel => this.generateToDbJobData('importFollowingToDb', { user, target: rel, withReplies })); return this.dbQueue.addBulk(jobs); } @@ -342,7 +343,7 @@ export class QueueService { } @bindThis - public createFollowJob(followings: { from: ThinUser, to: ThinUser, requestId?: string, silent?: boolean }[]) { + public createFollowJob(followings: { from: ThinUser, to: ThinUser, requestId?: string, silent?: boolean, withReplies?: boolean }[]) { const jobs = followings.map(rel => this.generateRelationshipJobData('follow', rel)); return this.relationshipQueue.addBulk(jobs); } diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index 2b5e41a12de9..6ec8fb76dfbe 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -56,7 +56,7 @@ export class ImportFollowingProcessorService { const csv = await this.downloadService.downloadTextFile(file.url); const targets = csv.trim().split('\n'); - this.queueService.createImportFollowingToDbJob({ id: user.id }, targets); + this.queueService.createImportFollowingToDbJob({ id: user.id }, targets, job.data.withReplies); this.logger.succ('Import jobs created'); } @@ -95,7 +95,7 @@ export class ImportFollowingProcessorService { this.logger.info(`Follow ${target.id} ...`); - this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true }]); + this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: job.data.withReplies }]); } catch (e) { this.logger.warn(`Error: ${e}`); } diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index ec6c55d11e2d..6c089b7a8969 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -37,7 +37,8 @@ export class RelationshipProcessorService { this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id}`); await this.userFollowingService.follow(job.data.from, job.data.to, { requestId: job.data.requestId, - silent: job.data.silent + silent: job.data.silent, + withReplies: job.data.withReplies, }); return 'ok'; } diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index c9122f5ca2ef..9330c01528f5 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -32,6 +32,7 @@ export type RelationshipJobData = { to: ThinUser; silent?: boolean; requestId?: string; + withReplies?: boolean; } export type DbJobData = DbJobMap[T]; @@ -79,6 +80,7 @@ export type DbUserDeleteJobData = { export type DbUserImportJobData = { user: ThinUser; fileId: MiDriveFile['id']; + withReplies?: boolean; }; export type DBAntennaImportJobData = { @@ -89,6 +91,7 @@ export type DBAntennaImportJobData = { export type DbUserImportToDbJobData = { user: ThinUser; target: string; + withReplies?: boolean; }; export type ObjectStorageJobData = ObjectStorageFileJobData | Record; diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts index 38c9283043ab..e5fa2ac96a12 100644 --- a/packages/backend/src/server/api/endpoints/i/import-following.ts +++ b/packages/backend/src/server/api/endpoints/i/import-following.ts @@ -52,6 +52,7 @@ export const paramDef = { type: 'object', properties: { fileId: { type: 'string', format: 'misskey:id' }, + withReplies: { type: 'boolean' }, }, required: ['fileId'], } as const; @@ -79,7 +80,7 @@ export default class extends Endpoint { // eslint- ); if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile); - this.queueService.createImportFollowingJob(me, file.id); + this.queueService.createImportFollowingJob(me, file.id, ps.withReplies); }); } } From 2862d362b59aae17c1cb1173c3ecb23bc08ba5d0 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 17:20:10 +0900 Subject: [PATCH 20/26] feat(frontend): configure withReplies --- locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + packages/frontend/src/pages/settings/import-export.vue | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 46514ed20024..f4fa056867b6 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2052,6 +2052,7 @@ export interface Locale { "userLists": string; "excludeMutingUsers": string; "excludeInactiveUsers": string; + "withReplies": string; }; "_charts": { "federation": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index fad5612b62d3..898ac3c33dbd 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1967,6 +1967,7 @@ _exportOrImport: userLists: "リスト" excludeMutingUsers: "ミュートしているユーザーを除外" excludeInactiveUsers: "使われていないアカウントを除外" + withReplies: "インポートした人による返信をTLに含むようにする" _charts: federation: "連合" diff --git a/packages/frontend/src/pages/settings/import-export.vue b/packages/frontend/src/pages/settings/import-export.vue index 0574a878aee5..20ee74df991f 100644 --- a/packages/frontend/src/pages/settings/import-export.vue +++ b/packages/frontend/src/pages/settings/import-export.vue @@ -40,6 +40,9 @@ SPDX-License-Identifier: AGPL-3.0-only + + {{ i18n.ts._exportOrImport.withReplies }} + {{ i18n.ts.import }}
@@ -118,9 +121,11 @@ import { selectFile } from '@/scripts/select-file.js'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { $i } from '@/account.js'; +import { defaultStore } from "@/store.js"; const excludeMutingUsers = ref(false); const excludeInactiveUsers = ref(false); +const withReplies = ref(defaultStore.state.defaultWithReplies); const onExportSuccess = () => { os.alert({ @@ -177,7 +182,7 @@ const exportAntennas = () => { const importFollowing = async (ev) => { const file = await selectFile(ev.currentTarget ?? ev.target); - os.api('i/import-following', { fileId: file.id }).then(onImportSuccess).catch(onError); + os.api('i/import-following', { fileId: file.id, withReplies }).then(onImportSuccess).catch(onError); }; const importUserLists = async (ev) => { From 9a941941b00119c3fce4ff722a16b878dec535e0 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 17:35:22 +0900 Subject: [PATCH 21/26] fix(frontend): incorrectly showRepliesToOthersInTimeline can be shown --- packages/frontend/src/components/MkFollowButton.vue | 1 + packages/frontend/src/pages/follow.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index cd8c88f23a73..c4103ce3c61c 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -98,6 +98,7 @@ async function onClick() { userId: props.user.id, withReplies: defaultStore.state.defaultWithReplies, }); + props.user.withReplies = defaultStore.state.defaultWithReplies; hasPendingFollowRequestFromYou = true; claimAchievement('following1'); diff --git a/packages/frontend/src/pages/follow.vue b/packages/frontend/src/pages/follow.vue index 482071e9b41d..a0a4a480b577 100644 --- a/packages/frontend/src/pages/follow.vue +++ b/packages/frontend/src/pages/follow.vue @@ -31,6 +31,7 @@ async function follow(user): Promise { userId: user.id, withReplies: defaultStore.state.defaultWithReplies, }); + user.withReplies = defaultStore.state.defaultWithReplies; } const acct = new URL(location.href).searchParams.get('acct'); From da5a0b5336953f43fa5984e9b221037b951b81ca Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 17:37:58 +0900 Subject: [PATCH 22/26] fix(backend): withReplies of following/create not working --- packages/backend/src/server/api/endpoints/following/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index bb55b2c4ec0f..9037944ef9ef 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -113,7 +113,7 @@ export default class extends Endpoint { // eslint- } try { - await this.userFollowingService.follow(follower, followee, {}); + await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies }); } catch (e) { if (e instanceof IdentifiableError) { if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); From bc554fb40b9472b2dc77086130051b06e09e0fca Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 17:43:59 +0900 Subject: [PATCH 23/26] fix(frontend): importFollowing error --- packages/frontend/src/pages/settings/import-export.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/settings/import-export.vue b/packages/frontend/src/pages/settings/import-export.vue index 20ee74df991f..0f01fda26f03 100644 --- a/packages/frontend/src/pages/settings/import-export.vue +++ b/packages/frontend/src/pages/settings/import-export.vue @@ -182,7 +182,10 @@ const exportAntennas = () => { const importFollowing = async (ev) => { const file = await selectFile(ev.currentTarget ?? ev.target); - os.api('i/import-following', { fileId: file.id, withReplies }).then(onImportSuccess).catch(onError); + os.api('i/import-following', { + fileId: file.id, + withReplies: withReplies.value, + }).then(onImportSuccess).catch(onError); }; const importUserLists = async (ev) => { From 29c848a3e1e815ce517fed37583be58912220544 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 18:06:01 +0900 Subject: [PATCH 24/26] fix: withReplies is not working with follow import --- packages/backend/src/core/QueueService.ts | 1 + .../src/queue/processors/ImportFollowingProcessorService.ts | 2 +- .../src/queue/processors/RelationshipProcessorService.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 55b24f0ad2f7..be378a899b4e 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -385,6 +385,7 @@ export class QueueService { to: { id: data.to.id }, silent: data.silent, requestId: data.requestId, + withReplies: data.withReplies, }, opts: { removeOnComplete: true, diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index 6ec8fb76dfbe..e75499a56f84 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -93,7 +93,7 @@ export class ImportFollowingProcessorService { // skip myself if (target.id === job.data.user.id) return; - this.logger.info(`Follow ${target.id} ...`); + this.logger.info(`Follow ${target.id} ${job.data.withReplies ? 'with replies' : 'without replies'} ...`); this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: job.data.withReplies }]); } catch (e) { diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index 6c089b7a8969..b2d8e3631f3b 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -34,7 +34,7 @@ export class RelationshipProcessorService { @bindThis public async processFollow(job: Bull.Job): Promise { - this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id}`); + this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? "with replies" : "without replies"}`); await this.userFollowingService.follow(job.data.from, job.data.to, { requestId: job.data.requestId, silent: job.data.silent, From 928400203ab48ee29e029f82f069006725bca3c3 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 21:38:24 +0900 Subject: [PATCH 25/26] fix(frontend): use v-model --- packages/frontend/src/components/MkFollowButton.vue | 9 ++++++++- packages/frontend/src/components/MkUserPopup.vue | 2 +- packages/frontend/src/pages/gallery/post.vue | 2 +- packages/frontend/src/pages/user/home.vue | 5 +++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index c4103ce3c61c..a10e7dfd4993 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -53,6 +53,10 @@ const props = withDefaults(defineProps<{ large: false, }); +const emit = defineEmits<{ + (e: 'update:user', value: Misskey.entities.UserDetailed): void +}>(); + let isFollowing = $ref(props.user.isFollowing); let hasPendingFollowRequestFromYou = $ref(props.user.hasPendingFollowRequestFromYou); let wait = $ref(false); @@ -98,7 +102,10 @@ async function onClick() { userId: props.user.id, withReplies: defaultStore.state.defaultWithReplies, }); - props.user.withReplies = defaultStore.state.defaultWithReplies; + emit('update:user', { + ...props.user, + withReplies: defaultStore.state.defaultWithReplies + }) hasPendingFollowRequestFromYou = true; claimAchievement('following1'); diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index 33ef07d54b79..dcdcf2238f30 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only - +
diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue index 3f4f657e9472..3863348eaef5 100644 --- a/packages/frontend/src/pages/gallery/post.vue +++ b/packages/frontend/src/pages/gallery/post.vue @@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- + diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 605e9fbb7639..4c425898d5d3 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.followsYou }}
- +
@@ -198,6 +198,7 @@ const props = withDefaults(defineProps<{ const router = useRouter(); +let user = $ref(props.user); let parallaxAnimationId = $ref(null); let narrow = $ref(null); let rootEl = $ref(null); @@ -232,7 +233,7 @@ const age = $computed(() => { }); function menu(ev) { - const { menu, cleanup } = getUserMenu(props.user, router); + const { menu, cleanup } = getUserMenu(user, router); os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup); } From 148beb6a60bd765b10245c5a45d9478b686d1627 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 16 Oct 2023 21:48:58 +0900 Subject: [PATCH 26/26] style: fix lint --- packages/frontend/src/components/MkFollowButton.vue | 4 ++-- packages/frontend/src/components/MkUserPopup.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index a10e7dfd4993..b8de71e3b721 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -54,7 +54,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (e: 'update:user', value: Misskey.entities.UserDetailed): void + (_: 'update:user', value: Misskey.entities.UserDetailed): void }>(); let isFollowing = $ref(props.user.isFollowing); @@ -105,7 +105,7 @@ async function onClick() { emit('update:user', { ...props.user, withReplies: defaultStore.state.defaultWithReplies - }) + }); hasPendingFollowRequestFromYou = true; claimAchievement('following1'); diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index dcdcf2238f30..bcba4196b55f 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only - +