Skip to content

Commit

Permalink
fix(frontend): リノートの判定が甘いのを修正 (#14396)
Browse files Browse the repository at this point in the history
* fix(frontend): リノートの判定が甘いのを修正

* fix

* Update Changelog

* fix

* use type assertion

* fix + add comments

* lint

* misskey-jsに移動

* PureRenote -> Renote

* isRenote -> isPureRenote
  • Loading branch information
kakkokari-gtyih authored Aug 17, 2024
1 parent 61cc3b5 commit 059eb6d
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 46 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Fix: iOSでユーザー名などがリンクとして誤検知される現象を抑制
- Fix: mCaptchaを使用していてもbotプロテクションに関する警告が消えないのを修正
- Fix: ユーザーのモデレーションページにおいてユーザー名にドットが入っているとシステムアカウントとして表示されてしまう問題を修正
- Fix: 特定の条件下でノートの削除ボタンが出ないのを修正

### Server
- Enhance: 凍結されたアカウントのフォローリクエストを表示しないように
Expand Down
12 changes: 3 additions & 9 deletions packages/frontend/src/components/MkNote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ import { host } from '@/config.js';
import { isEnabledUrlPreview } from '@/instance.js';
import { type Keymap } from '@/scripts/hotkey.js';
import { focusPrev, focusNext } from '@/scripts/focus.js';
import { getAppearNote } from '@/scripts/get-appear-note.js';

const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
Expand Down Expand Up @@ -242,22 +243,15 @@ if (noteViewInterruptors.length > 0) {
});
}

const isRenote = (
note.value.renote != null &&
note.value.reply == null &&
note.value.text == null &&
note.value.cw == null &&
note.value.fileIds && note.value.fileIds.length === 0 &&
note.value.poll == null
);
const isRenote = Misskey.note.isPureRenote(note.value);

const rootEl = shallowRef<HTMLElement>();
const menuButton = shallowRef<HTMLElement>();
const renoteButton = shallowRef<HTMLElement>();
const renoteTime = shallowRef<HTMLElement>();
const reactButton = shallowRef<HTMLElement>();
const clipButton = shallowRef<HTMLElement>();
const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
const appearNote = computed(() => getAppearNote(note.value));
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(false);
Expand Down
12 changes: 3 additions & 9 deletions packages/frontend/src/components/MkNoteDetailed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ import MkPagination, { type Paging } from '@/components/MkPagination.vue';
import MkReactionIcon from '@/components/MkReactionIcon.vue';
import MkButton from '@/components/MkButton.vue';
import { isEnabledUrlPreview } from '@/instance.js';
import { getAppearNote } from '@/scripts/get-appear-note.js';
import { type Keymap } from '@/scripts/hotkey.js';

const props = withDefaults(defineProps<{
Expand Down Expand Up @@ -267,22 +268,15 @@ if (noteViewInterruptors.length > 0) {
});
}

const isRenote = (
note.value.renote != null &&
note.value.reply == null &&
note.value.text == null &&
note.value.cw == null &&
note.value.fileIds && note.value.fileIds.length === 0 &&
note.value.poll == null
);
const isRenote = Misskey.note.isPureRenote(note.value);

const rootEl = shallowRef<HTMLElement>();
const menuButton = shallowRef<HTMLElement>();
const renoteButton = shallowRef<HTMLElement>();
const renoteTime = shallowRef<HTMLElement>();
const reactButton = shallowRef<HTMLElement>();
const clipButton = shallowRef<HTMLElement>();
const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
const appearNote = computed(() => getAppearNote(note.value));
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(false);
Expand Down
10 changes: 10 additions & 0 deletions packages/frontend/src/scripts/get-appear-note.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/

import * as Misskey from 'misskey-js';

export function getAppearNote(note: Misskey.entities.Note) {
return Misskey.note.isPureRenote(note) ? note.renote : note;
}
33 changes: 7 additions & 26 deletions packages/frontend/src/scripts/get-note-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { clipsCache, favoritedChannelsCache } from '@/cache.js';
import { MenuItem } from '@/types/menu.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { isSupportShare } from '@/scripts/navigator.js';
import { getAppearNote } from '@/scripts/get-appear-note.js';

export async function getNoteClipMenu(props: {
note: Misskey.entities.Note;
Expand All @@ -34,14 +35,7 @@ export async function getNoteClipMenu(props: {
}
}

const isRenote = (
props.note.renote != null &&
props.note.text == null &&
props.note.fileIds.length === 0 &&
props.note.poll == null
);

const appearNote = isRenote ? props.note.renote as Misskey.entities.Note : props.note;
const appearNote = getAppearNote(props.note);

const clips = await clipsCache.fetch();
const menu: MenuItem[] = [...clips.map(clip => ({
Expand Down Expand Up @@ -164,14 +158,7 @@ export function getNoteMenu(props: {
isDeleted: Ref<boolean>;
currentClip?: Misskey.entities.Clip;
}) {
const isRenote = (
props.note.renote != null &&
props.note.text == null &&
props.note.fileIds.length === 0 &&
props.note.poll == null
);

const appearNote = isRenote ? props.note.renote as Misskey.entities.Note : props.note;
const appearNote = getAppearNote(props.note);

const cleanups = [] as (() => void)[];

Expand Down Expand Up @@ -248,6 +235,7 @@ export function getNoteMenu(props: {
}

async function unclip(): Promise<void> {
if (!props.currentClip) return;
os.apiWithDialog('clips/remove-note', { clipId: props.currentClip.id, noteId: appearNote.id });
props.isDeleted.value = true;
}
Expand All @@ -267,8 +255,8 @@ export function getNoteMenu(props: {

function share(): void {
navigator.share({
title: i18n.tsx.noteOf({ user: appearNote.user.name }),
text: appearNote.text,
title: i18n.tsx.noteOf({ user: appearNote.user.name ?? appearNote.user.username }),
text: appearNote.text ?? '',
url: `${url}/notes/${appearNote.id}`,
});
}
Expand Down Expand Up @@ -509,14 +497,7 @@ export function getRenoteMenu(props: {
renoteButton: ShallowRef<HTMLElement | undefined>;
mock?: boolean;
}) {
const isRenote = (
props.note.renote != null &&
props.note.text == null &&
props.note.fileIds.length === 0 &&
props.note.poll == null
);

const appearNote = isRenote ? props.note.renote as Misskey.entities.Note : props.note;
const appearNote = getAppearNote(props.note);

const channelRenoteItems: MenuItem[] = [];
const normalRenoteItems: MenuItem[] = [];
Expand Down
22 changes: 21 additions & 1 deletion packages/misskey-js/etc/misskey-js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,7 @@ declare namespace entities {
export {
ID,
DateString,
PureRenote,
PageEvent,
ModerationLog,
ServerStats,
Expand Down Expand Up @@ -2277,6 +2278,9 @@ type ISigninHistoryRequest = operations['i___signin-history']['requestBody']['co
// @public (undocumented)
type ISigninHistoryResponse = operations['i___signin-history']['responses']['200']['content']['application/json'];

// @public (undocumented)
function isPureRenote(note: Note): note is PureRenote;

// @public (undocumented)
type IUnpinRequest = operations['i___unpin']['requestBody']['content']['application/json'];

Expand Down Expand Up @@ -2513,6 +2517,13 @@ type MyAppsResponse = operations['my___apps']['responses']['200']['content']['ap
// @public (undocumented)
type Note = components['schemas']['Note'];

declare namespace note {
export {
isPureRenote
}
}
export { note }

// @public (undocumented)
type NoteFavorite = components['schemas']['NoteFavorite'];

Expand Down Expand Up @@ -2753,6 +2764,15 @@ type PinnedUsersResponse = operations['pinned-users']['responses']['200']['conte
// @public (undocumented)
type PromoReadRequest = operations['promo___read']['requestBody']['content']['application/json'];

// Warning: (ae-forgotten-export) The symbol "AllNullRecord" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "NonNullableRecord" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
type PureRenote = Omit<Note, 'renote' | 'renoteId' | 'reply' | 'replyId' | 'text' | 'cw' | 'files' | 'fileIds' | 'poll'> & AllNullRecord<Pick<Note, 'reply' | 'replyId' | 'text' | 'cw' | 'poll'>> & {
files: [];
fileIds: [];
} & NonNullableRecord<Pick<Note, 'renote' | 'renoteId'>>;

// @public (undocumented)
type QueueCount = components['schemas']['QueueCount'];

Expand Down Expand Up @@ -3232,7 +3252,7 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['

// Warnings were encountered during analysis:
//
// src/entities.ts:35:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
// src/entities.ts:49:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:220:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:230:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" needs to be exported by the entry point index.d.ts

Expand Down
14 changes: 14 additions & 0 deletions packages/misskey-js/src/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Announcement,
EmojiDetailed,
MeDetailed,
Note,
Page,
Role,
RolePolicies,
Expand All @@ -16,6 +17,19 @@ export * from './autogen/models.js';
export type ID = string;
export type DateString = string;

type NonNullableRecord<T> = {
[P in keyof T]-?: NonNullable<T[P]>;
};
type AllNullRecord<T> = {
[P in keyof T]: null;
};

export type PureRenote =
Omit<Note, 'renote' | 'renoteId' | 'reply' | 'replyId' | 'text' | 'cw' | 'files' | 'fileIds' | 'poll'>
& AllNullRecord<Pick<Note, 'reply' | 'replyId' | 'text' | 'cw' | 'poll'>>
& { files: []; fileIds: []; }
& NonNullableRecord<Pick<Note, 'renote' | 'renoteId'>>;

export type PageEvent = {
pageId: Page['id'];
event: string;
Expand Down
3 changes: 2 additions & 1 deletion packages/misskey-js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ export const reversiUpdateKeys = consts.reversiUpdateKeys;
import * as api from './api.js';
import * as entities from './entities.js';
import * as acct from './acct.js';
export { api, entities, acct };
import * as note from './note.js';
export { api, entities, acct, note };
12 changes: 12 additions & 0 deletions packages/misskey-js/src/note.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Note, PureRenote } from './entities.js';

export function isPureRenote(note: Note): note is PureRenote {
return (
note.renote != null &&
note.reply == null &&
note.text == null &&
note.cw == null &&
(note.fileIds == null || note.fileIds.length === 0) &&
note.poll == null
);
}

0 comments on commit 059eb6d

Please sign in to comment.