フロント側でもリアクション権限のチェックをするように

This commit is contained in:
1Step621 2024-02-02 02:44:16 +09:00
parent 30b48df9d9
commit 84fc05d080
6 changed files with 96 additions and 5 deletions

18
locales/index.d.ts vendored
View File

@ -500,6 +500,24 @@ export interface Locale extends ILocale {
*
*/
"reactions": string;
/**
*
*/
"reactionDenied": string;
"_reactionDeniedReason": {
/**
* 稿
*/
"isSensitive": string;
/**
*
*/
"localOnly": string;
/**
* 使
*/
"roleIdsThatCanBeUsedThisEmojiAsReaction": string;
};
/**
*
*/

View File

@ -121,6 +121,11 @@ sensitive: "センシティブ"
add: "追加"
reaction: "リアクション"
reactions: "リアクション"
reactionDenied: "このリアクションをつける権限がありません。"
_reactionDeniedReason:
isSensitive: "投稿者がセンシティブなリアクションを許可していないため、リアクションできません。"
localOnly: "この絵文字はリモートから見られないように設定されているため、リアクションできません。"
roleIdsThatCanBeUsedThisEmojiAsReaction: "この絵文字をリアクションとして使うにはロールが必要です。"
emojiPicker: "絵文字ピッカー"
pinnedEmojisForReactionSettingDescription: "リアクション時にピン留め表示する絵文字を設定できます"
pinnedEmojisSettingDescription: "絵文字入力時にピン留め表示する絵文字を設定できます"

View File

@ -193,6 +193,7 @@ import { MenuItem } from '@/types/menu.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
import { shouldCollapsed } from '@/scripts/collapsed.js';
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
@ -380,7 +381,21 @@ function react(viaKeyboard = false): void {
}
} else {
blur();
reactionPicker.show(reactButton.value ?? null, reaction => {
reactionPicker.show(reactButton.value ?? null, async reaction => {
if (reaction.includes(':')) {
const permissions = checkReactionPermissions($i!, props.note, await misskeyApi('emoji', {
name: reaction.replace(/:/g, '').replace(/@\./, ''),
}));
if (!permissions.allowed) {
os.alert({
type: "info",
title: i18n.ts.reactionDenied,
text: i18n.ts._reactionDeniedReason[permissions.deniedReason],
});
return;
}
}
sound.playMisskeySfx('reaction');
if (props.mock) {

View File

@ -228,6 +228,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkPagination, { type Paging } from '@/components/MkPagination.vue';
import MkReactionIcon from '@/components/MkReactionIcon.vue';
import MkButton from '@/components/MkButton.vue';
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
const props = defineProps<{
note: Misskey.entities.Note;
@ -385,7 +386,21 @@ function react(viaKeyboard = false): void {
}
} else {
blur();
reactionPicker.show(reactButton.value ?? null, reaction => {
reactionPicker.show(reactButton.value ?? null, async reaction => {
if (reaction.includes(':')) {
const permissions = checkReactionPermissions($i!, props.note, await misskeyApi('emoji', {
name: reaction.replace(/:/g, '').replace(/@\./, ''),
}));
if (!permissions.allowed) {
os.alert({
type: "info",
title: i18n.ts.reactionDenied,
text: i18n.ts._reactionDeniedReason[permissions.deniedReason],
});
return;
}
}
sound.playMisskeySfx('reaction');
misskeyApi('notes/reactions/create', {

View File

@ -32,6 +32,7 @@ import { claimAchievement } from '@/scripts/achievements.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import * as sound from '@/scripts/sound.js';
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
const props = defineProps<{
reaction: string;
@ -48,12 +49,30 @@ const emit = defineEmits<{
const buttonEl = shallowRef<HTMLElement>();
const canToggle = computed(() => !props.reaction.match(/@\w/) && $i);
const canToggle = computed(() => {
return $i && !props.reaction.match(/@\w/);
});
const canGetInfo = computed(() => {
return !props.reaction.match(/@\w/);
});
async function toggleReaction() {
if (!canToggle.value) return;
// TODO: 使
if (props.reaction.includes(':')) {
const permissions = checkReactionPermissions($i!, props.note, await misskeyApi('emoji', {
name: props.reaction.replace(/:/g, '').replace(/@\./, ''),
}));
if (!permissions.allowed) {
os.alert({
type: "info",
title: i18n.ts.reactionDenied,
text: i18n.ts._reactionDeniedReason[permissions.deniedReason],
});
return;
}
}
const oldReaction = props.note.myReaction;
if (oldReaction) {
@ -101,7 +120,7 @@ async function toggleReaction() {
}
async function menu(ev) {
if (!canToggle.value) return;
if (!canGetInfo.value) return;
if (!props.reaction.includes(':')) return;
os.popupMenu([{
text: i18n.ts.info,

View File

@ -0,0 +1,19 @@
import * as Misskey from 'misskey-js';
export function checkReactionPermissions(me: Misskey.entities.MeDetailed, note: Misskey.entities.Note, emoji: Misskey.entities.EmojiDetailed): {
allowed: true;
} | {
allowed: false;
deniedReason: 'localOnly' | 'isSensitive' | 'roleIdsThatCanBeUsedThisEmojiAsReaction';
} {
if (emoji.localOnly && note.user.host !== me.host) {
return { allowed: false, deniedReason: 'localOnly' }
};
if (emoji.isSensitive && (note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote')) {
return { allowed: false, deniedReason: 'isSensitive' }
}
if (!(emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0 || me.roles.some(role => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(role.id)))) {
return { allowed: false, deniedReason: 'roleIdsThatCanBeUsedThisEmojiAsReaction' }
}
return { allowed: true };
}