diff --git a/packages/backend/migration/1696807733453-userListUserId.js b/packages/backend/migration/1696807733453-userListUserId.js new file mode 100644 index 0000000000..ab2ba07fb5 --- /dev/null +++ b/packages/backend/migration/1696807733453-userListUserId.js @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class UserListUserId1696807733453 { + name = 'UserListUserId1696807733453' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_list_membership" ADD "userListUserId" character varying(32) NOT NULL DEFAULT ''`); + const memberships = await queryRunner.query(`SELECT "id", "userListId" FROM "user_list_membership"`); + for(let i = 0; i < memberships.length; i++) { + const userList = await queryRunner.query(`SELECT "userId" FROM "user_list" WHERE "id" = $1`, [memberships[i].userListId]); + await queryRunner.query(`UPDATE "user_list_membership" SET "userListUserId" = $1 WHERE "id" = $2`, [userList[0].userId, memberships[i].id]); + } + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_list_membership" DROP COLUMN "userListUserId"`); + } +} diff --git a/packages/backend/migration/1696808725134-userListUserId-2.js b/packages/backend/migration/1696808725134-userListUserId-2.js new file mode 100644 index 0000000000..5bcb5aedc2 --- /dev/null +++ b/packages/backend/migration/1696808725134-userListUserId-2.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class UserListUserId21696808725134 { + name = 'UserListUserId21696808725134' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_list_membership" ALTER COLUMN "userListUserId" DROP DEFAULT`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_list_membership" ALTER COLUMN "userListUserId" SET DEFAULT ''`); + } +} diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts index ba3413007d..db64f42754 100644 --- a/packages/backend/src/core/AccountMoveService.ts +++ b/packages/backend/src/core/AccountMoveService.ts @@ -228,7 +228,7 @@ export class AccountMoveService { }, }).then(memberships => memberships.map(membership => membership.userListId)); - const newMemberships: Map = new Map(); + const newMemberships: Map = new Map(); // 重複しないようにIDを生成 const genId = (): string => { @@ -244,6 +244,7 @@ export class AccountMoveService { createdAt: new Date(), userId: dst.id, userListId: membership.userListId, + userListUserId: membership.userListUserId, }); } diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts index bece1e442e..5b4e7a711e 100644 --- a/packages/backend/src/core/UserListService.ts +++ b/packages/backend/src/core/UserListService.ts @@ -97,6 +97,7 @@ export class UserListService implements OnApplicationShutdown { createdAt: new Date(), userId: target.id, userListId: list.id, + userListUserId: list.userId, } as MiUserListMembership); this.globalEventService.publishInternalEvent('userListMemberAdded', { userListId: list.id, memberId: target.id }); diff --git a/packages/backend/src/models/UserListMembership.ts b/packages/backend/src/models/UserListMembership.ts index f337f19a47..f57f9ac33d 100644 --- a/packages/backend/src/models/UserListMembership.ts +++ b/packages/backend/src/models/UserListMembership.ts @@ -50,4 +50,11 @@ export class MiUserListMembership { default: false, }) public withReplies: boolean; + + //#region Denormalized fields + @Column({ + ...id(), + }) + public userListUserId: MiUser['id']; + //#endregion } diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 71aa6e661c..d4f9186e3a 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -114,7 +114,7 @@ export default class extends Endpoint { // eslint- noteIds = noteIds.slice(0, ps.limit); if (noteIds.length > 0) { - const isFollowing = me ? Object.hasOwn(await this.cacheService.userFollowingsCache.fetch(me.id), ps.userId) : false; + const isFollowing = me ? me.id === ps.userId || Object.hasOwn(await this.cacheService.userFollowingsCache.fetch(me.id), ps.userId) : false; const query = this.notesRepository.createQueryBuilder('note') .where('note.id IN (:...noteIds)', { noteIds: noteIds }) diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index 49256cba34..6de58f0146 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -820,6 +820,19 @@ describe('Timelines', () => { assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); }); + test.concurrent('自身の visibility: followers なノートが含まれる', async () => { + const [alice] = await Promise.all([signup()]); + + const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' }); + + await waitForPushToTl(); + + const res = await api('/users/notes', { userId: alice.id }, alice); + + assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); + assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); + }); + test.concurrent('チャンネル投稿が含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index 234de7e29e..f67697db55 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -187,6 +187,9 @@ const patronsWithIcon = [{ }, { name: 'フランギ・シュウ', icon: 'https://misskey-hub.net/patrons/3016d37e35f3430b90420176c912d304.jpg', +}, { + name: '百日紅', + icon: 'https://misskey-hub.net/patrons/302dce2898dd457ba03c3f7dc037900b.jpg', }]; const patrons = [