From 4d331f445c333acc1df9bb52af2165ca31c94fef Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 29 Apr 2024 15:52:49 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20=E8=A4=87=E6=95=B0id=E3=82=92?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E3=81=99=E3=82=8B`users/show`=E3=81=8C?= =?UTF-8?q?=E9=96=A2=E4=BF=82=E3=81=AA=E3=81=84=E3=83=A6=E3=83=BC=E3=82=B6?= =?UTF-8?q?=E3=82=92=E8=BF=94=E3=81=99=E3=81=93=E3=81=A8=E3=81=8C=E3=81=82?= =?UTF-8?q?=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + packages/backend/src/misc/json-schema.ts | 2 +- packages/backend/src/server/api/endpoints/users/show.ts | 7 ++++--- packages/frontend/src/account.ts | 2 +- packages/frontend/src/components/MkAvatars.vue | 4 ++-- packages/frontend/src/components/MkPostForm.vue | 9 +++------ packages/frontend/src/components/MkUserSelectDialog.vue | 1 + packages/frontend/src/pages/list.vue | 2 +- packages/frontend/src/pages/settings/accounts.vue | 2 +- packages/frontend/src/pages/settings/migration.vue | 4 ++-- packages/frontend/src/widgets/WidgetUserList.vue | 2 +- packages/misskey-js/etc/misskey-js.api.md | 2 +- packages/misskey-js/src/api.types.ts | 2 +- packages/misskey-js/src/autogen/types.ts | 2 +- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68015596bdcc..bd3781bf4c80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ - Fix: グローバルタイムラインで返信が表示されないことがある問題を修正 - Fix: リノートをミュートしたユーザの投稿のリノートがミュートされる問題を修正 - Fix: AP Link等は添付ファイル扱いしないようになど (#13754) +- Fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正 ## 2024.3.1 diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index a620d7c94b8c..41e5bfe9e4ad 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -228,7 +228,7 @@ export type SchemaTypeDef

= p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] : never ) : - p['items'] extends NonNullable ? SchemaTypeDef[] : + p['items'] extends NonNullable ? SchemaType[] : any[] ) : p['anyOf'] extends ReadonlyArray ? UnionSchemaType & PartialIntersection> : diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index bd81989cb9c4..005600f87468 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -36,6 +36,7 @@ export const meta = { items: { type: 'object', ref: 'UserDetailed', + nullable: true, }, }, ], @@ -110,12 +111,12 @@ export default class extends Endpoint { // eslint- }); // リクエストされた通りに並べ替え - const _users: MiUser[] = []; + const _users: (MiUser | null)[] = []; for (const id of ps.userIds) { - _users.push(users.find(x => x.id === id)!); + _users.push(users.find(x => x.id === id) ?? null); } - return await Promise.all(_users.map(u => this.userEntityService.pack(u, me, { + return await Promise.all(_users.map(u => u == null ? null : this.userEntityService.pack(u, me, { schema: 'UserDetailed', }))); } else { diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index 7f20e0b1a275..4e60b6ae47d6 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -271,7 +271,7 @@ export async function openAccountMenu(opts: { const accountItemPromises = storedAccounts.map(a => new Promise | MenuButton>(res => { accountsPromise.then(accounts => { - const account = accounts.find(x => x.id === a.id); + const account = accounts.find(x => x?.id === a.id); if (account == null) return res({ type: 'button' as const, text: a.id, diff --git a/packages/frontend/src/components/MkAvatars.vue b/packages/frontend/src/components/MkAvatars.vue index 8236d0ddb94d..7b0a340b7ffe 100644 --- a/packages/frontend/src/components/MkAvatars.vue +++ b/packages/frontend/src/components/MkAvatars.vue @@ -27,8 +27,8 @@ const props = withDefaults(defineProps<{ const users = ref([]); onMounted(async () => { - users.value = await misskeyApi('users/show', { + users.value = (await misskeyApi('users/show', { userIds: props.userIds, - }) as unknown as Misskey.entities.UserLite[]; + })).filter(x => x != null); }); diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index d7efca9de9c9..19665fa2d46b 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -536,7 +536,8 @@ async function toggleReactionAcceptance() { reactionAcceptance.value = select.result; } -function pushVisibleUser(user: Misskey.entities.UserDetailed) { +function pushVisibleUser(user: Misskey.entities.UserDetailed | null) { + if (user == null) return; if (!visibleUsers.value.some(u => u.username === user.username && u.host === user.host)) { visibleUsers.value.push(user); } @@ -963,11 +964,7 @@ onMounted(() => { } if (draft.data.visibleUserIds) { misskeyApi('users/show', { userIds: draft.data.visibleUserIds }).then(users => { - for (let i = 0; i < users.length; i++) { - if (users[i].id === draft.data.visibleUserIds[i]) { - pushVisibleUser(users[i]); - } - } + users.forEach(pushVisibleUser); }); } } diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue index cc3ea78ffe6f..3d0850f9d4f1 100644 --- a/packages/frontend/src/components/MkUserSelectDialog.vue +++ b/packages/frontend/src/components/MkUserSelectDialog.vue @@ -141,6 +141,7 @@ onMounted(() => { userIds: defaultStore.state.recentlyUsedUsers, }).then(foundUsers => { let _users = foundUsers; + _users = _users.filter(u => u != null); _users = _users.filter((u) => { if (props.localOnly) { return u.host == null; diff --git a/packages/frontend/src/pages/list.vue b/packages/frontend/src/pages/list.vue index 954246ff93f9..8caac32cf2e5 100644 --- a/packages/frontend/src/pages/list.vue +++ b/packages/frontend/src/pages/list.vue @@ -62,7 +62,7 @@ function fetchList(): void { misskeyApi('users/show', { userIds: list.value.userIds, }).then(_users => { - users.value = _users; + users.value = _users.filter(u => u != null); }); }).catch(err => { error.value = err; diff --git a/packages/frontend/src/pages/settings/accounts.vue b/packages/frontend/src/pages/settings/accounts.vue index 1182346de96f..fb80f25a72c5 100644 --- a/packages/frontend/src/pages/settings/accounts.vue +++ b/packages/frontend/src/pages/settings/accounts.vue @@ -41,7 +41,7 @@ const init = async () => { userIds: storedAccounts.value.map(x => x.id), }); }).then(response => { - accounts.value = response; + accounts.value = response.filter(u => u != null); }); }; diff --git a/packages/frontend/src/pages/settings/migration.vue b/packages/frontend/src/pages/settings/migration.vue index ddc23945dd58..28bede4c56da 100644 --- a/packages/frontend/src/pages/settings/migration.vue +++ b/packages/frontend/src/pages/settings/migration.vue @@ -86,8 +86,8 @@ async function init() { } if ($i.alsoKnownAs && $i.alsoKnownAs.length > 0) { - const alsoKnownAs = await misskeyApi('users/show', { userIds: $i.alsoKnownAs }); - accountAliases.value = (alsoKnownAs && alsoKnownAs.length > 0) ? alsoKnownAs.map(user => `@${Misskey.acct.toString(user)}`) : ['']; + const alsoKnownAs = (await misskeyApi('users/show', { userIds: $i.alsoKnownAs })).filter(u => u != null); + accountAliases.value = (alsoKnownAs.length > 0) ? alsoKnownAs.map(user => `@${Misskey.acct.toString(user)}`) : ['']; } else { accountAliases.value = ['']; } diff --git a/packages/frontend/src/widgets/WidgetUserList.vue b/packages/frontend/src/widgets/WidgetUserList.vue index d9f4dc49ea87..399a1d7b9b73 100644 --- a/packages/frontend/src/widgets/WidgetUserList.vue +++ b/packages/frontend/src/widgets/WidgetUserList.vue @@ -93,7 +93,7 @@ const fetch = () => { misskeyApi('users/show', { userIds: list.value.userIds, }).then(_users => { - users.value = _users; + users.value = _users.filter(u => u != null); fetching.value = false; }); }); diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 9720b04e3963..9aef1b10bf82 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1078,7 +1078,7 @@ export type Endpoints = Overwrite Date: Mon, 29 Apr 2024 15:59:01 +0900 Subject: [PATCH 2/4] test: fix misskey js test --- packages/misskey-js/test-d/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/misskey-js/test-d/api.ts b/packages/misskey-js/test-d/api.ts index 4b72ff4e9da5..7eab3bc852fe 100644 --- a/packages/misskey-js/test-d/api.ts +++ b/packages/misskey-js/test-d/api.ts @@ -40,6 +40,6 @@ describe('API', () => { expectType(res); const res2 = await cli.request('users/show', { userIds: ['xxxxxxxx'] }); - expectType(res2); + expectType<(Misskey.entities.UserDetailed | null)[]>(res2); }); }); From 5e631114683c64e845bd23021e02b7d67ee8dc83 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 29 Apr 2024 23:50:16 +0900 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20user/show=E3=81=8Cnull=E3=82=92?= =?UTF-8?q?=E8=BF=94=E3=81=95=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/api/endpoints/users/show.ts | 9 +++++---- packages/frontend/src/account.ts | 2 +- packages/frontend/src/components/MkAvatars.vue | 4 ++-- packages/frontend/src/components/MkPostForm.vue | 3 +-- packages/frontend/src/components/MkUserSelectDialog.vue | 1 - packages/frontend/src/pages/list.vue | 2 +- packages/frontend/src/pages/settings/accounts.vue | 2 +- packages/frontend/src/pages/settings/migration.vue | 4 ++-- packages/frontend/src/widgets/WidgetUserList.vue | 2 +- packages/misskey-js/etc/misskey-js.api.md | 2 +- packages/misskey-js/src/api.types.ts | 2 +- packages/misskey-js/src/autogen/types.ts | 2 +- packages/misskey-js/test-d/api.ts | 2 +- 13 files changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 005600f87468..26cfa921c56a 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -36,7 +36,6 @@ export const meta = { items: { type: 'object', ref: 'UserDetailed', - nullable: true, }, }, ], @@ -111,12 +110,14 @@ export default class extends Endpoint { // eslint- }); // リクエストされた通りに並べ替え - const _users: (MiUser | null)[] = []; + // 順番は保持されるけど数は減ってる可能性がある + const _users: MiUser[] = []; for (const id of ps.userIds) { - _users.push(users.find(x => x.id === id) ?? null); + const user = users.find(x => x.id === id); + if (user != null) _users.push(user); } - return await Promise.all(_users.map(u => u == null ? null : this.userEntityService.pack(u, me, { + return await Promise.all(_users.map(u => this.userEntityService.pack(u, me, { schema: 'UserDetailed', }))); } else { diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index 4e60b6ae47d6..7f20e0b1a275 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -271,7 +271,7 @@ export async function openAccountMenu(opts: { const accountItemPromises = storedAccounts.map(a => new Promise | MenuButton>(res => { accountsPromise.then(accounts => { - const account = accounts.find(x => x?.id === a.id); + const account = accounts.find(x => x.id === a.id); if (account == null) return res({ type: 'button' as const, text: a.id, diff --git a/packages/frontend/src/components/MkAvatars.vue b/packages/frontend/src/components/MkAvatars.vue index 7b0a340b7ffe..8236d0ddb94d 100644 --- a/packages/frontend/src/components/MkAvatars.vue +++ b/packages/frontend/src/components/MkAvatars.vue @@ -27,8 +27,8 @@ const props = withDefaults(defineProps<{ const users = ref([]); onMounted(async () => { - users.value = (await misskeyApi('users/show', { + users.value = await misskeyApi('users/show', { userIds: props.userIds, - })).filter(x => x != null); + }) as unknown as Misskey.entities.UserLite[]; }); diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 19665fa2d46b..49f787be7685 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -536,8 +536,7 @@ async function toggleReactionAcceptance() { reactionAcceptance.value = select.result; } -function pushVisibleUser(user: Misskey.entities.UserDetailed | null) { - if (user == null) return; +function pushVisibleUser(user: Misskey.entities.UserDetailed) { if (!visibleUsers.value.some(u => u.username === user.username && u.host === user.host)) { visibleUsers.value.push(user); } diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue index 3d0850f9d4f1..cc3ea78ffe6f 100644 --- a/packages/frontend/src/components/MkUserSelectDialog.vue +++ b/packages/frontend/src/components/MkUserSelectDialog.vue @@ -141,7 +141,6 @@ onMounted(() => { userIds: defaultStore.state.recentlyUsedUsers, }).then(foundUsers => { let _users = foundUsers; - _users = _users.filter(u => u != null); _users = _users.filter((u) => { if (props.localOnly) { return u.host == null; diff --git a/packages/frontend/src/pages/list.vue b/packages/frontend/src/pages/list.vue index 8caac32cf2e5..954246ff93f9 100644 --- a/packages/frontend/src/pages/list.vue +++ b/packages/frontend/src/pages/list.vue @@ -62,7 +62,7 @@ function fetchList(): void { misskeyApi('users/show', { userIds: list.value.userIds, }).then(_users => { - users.value = _users.filter(u => u != null); + users.value = _users; }); }).catch(err => { error.value = err; diff --git a/packages/frontend/src/pages/settings/accounts.vue b/packages/frontend/src/pages/settings/accounts.vue index fb80f25a72c5..1182346de96f 100644 --- a/packages/frontend/src/pages/settings/accounts.vue +++ b/packages/frontend/src/pages/settings/accounts.vue @@ -41,7 +41,7 @@ const init = async () => { userIds: storedAccounts.value.map(x => x.id), }); }).then(response => { - accounts.value = response.filter(u => u != null); + accounts.value = response; }); }; diff --git a/packages/frontend/src/pages/settings/migration.vue b/packages/frontend/src/pages/settings/migration.vue index 28bede4c56da..ddc23945dd58 100644 --- a/packages/frontend/src/pages/settings/migration.vue +++ b/packages/frontend/src/pages/settings/migration.vue @@ -86,8 +86,8 @@ async function init() { } if ($i.alsoKnownAs && $i.alsoKnownAs.length > 0) { - const alsoKnownAs = (await misskeyApi('users/show', { userIds: $i.alsoKnownAs })).filter(u => u != null); - accountAliases.value = (alsoKnownAs.length > 0) ? alsoKnownAs.map(user => `@${Misskey.acct.toString(user)}`) : ['']; + const alsoKnownAs = await misskeyApi('users/show', { userIds: $i.alsoKnownAs }); + accountAliases.value = (alsoKnownAs && alsoKnownAs.length > 0) ? alsoKnownAs.map(user => `@${Misskey.acct.toString(user)}`) : ['']; } else { accountAliases.value = ['']; } diff --git a/packages/frontend/src/widgets/WidgetUserList.vue b/packages/frontend/src/widgets/WidgetUserList.vue index 399a1d7b9b73..d9f4dc49ea87 100644 --- a/packages/frontend/src/widgets/WidgetUserList.vue +++ b/packages/frontend/src/widgets/WidgetUserList.vue @@ -93,7 +93,7 @@ const fetch = () => { misskeyApi('users/show', { userIds: list.value.userIds, }).then(_users => { - users.value = _users.filter(u => u != null); + users.value = _users; fetching.value = false; }); }); diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 9aef1b10bf82..9720b04e3963 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1078,7 +1078,7 @@ export type Endpoints = Overwrite { expectType(res); const res2 = await cli.request('users/show', { userIds: ['xxxxxxxx'] }); - expectType<(Misskey.entities.UserDetailed | null)[]>(res2); + expectType(res2); }); }); From bbd69b3e8de1ba3191c7dd5cf9c6bc3997cacf50 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 9 May 2024 09:14:55 +0900 Subject: [PATCH 4/4] chore: pass lambda instead of pushVisibleUser --- packages/frontend/src/components/MkPostForm.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 49f787be7685..a4bacc1962e6 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -189,7 +189,7 @@ const localOnly = ref(props.initialLocalOnly ?? defaultStore.state.reme const visibility = ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility) as typeof Misskey.noteVisibilities[number]); const visibleUsers = ref([]); if (props.initialVisibleUsers) { - props.initialVisibleUsers.forEach(pushVisibleUser); + props.initialVisibleUsers.forEach(u => pushVisibleUser(u)); } const reactionAcceptance = ref(defaultStore.state.reactionAcceptance); const autocomplete = ref(null); @@ -335,7 +335,7 @@ if (props.reply && ['home', 'followers', 'specified'].includes(props.reply.visib misskeyApi('users/show', { userIds: props.reply.visibleUserIds.filter(uid => uid !== $i.id && uid !== props.reply?.userId), }).then(users => { - users.forEach(pushVisibleUser); + users.forEach(u => pushVisibleUser(u)); }); } @@ -963,7 +963,7 @@ onMounted(() => { } if (draft.data.visibleUserIds) { misskeyApi('users/show', { userIds: draft.data.visibleUserIds }).then(users => { - users.forEach(pushVisibleUser); + users.forEach(u => pushVisibleUser(u)); }); } }