フロント側でもリアクション権限のチェックをするように
This commit is contained in:
parent
30b48df9d9
commit
84fc05d080
|
@ -500,6 +500,24 @@ export interface Locale extends ILocale {
|
|||
* リアクション
|
||||
*/
|
||||
"reactions": string;
|
||||
/**
|
||||
* このリアクションをつける権限がありません。
|
||||
*/
|
||||
"reactionDenied": string;
|
||||
"_reactionDeniedReason": {
|
||||
/**
|
||||
* 投稿者がセンシティブなリアクションを許可していないため、リアクションできません。
|
||||
*/
|
||||
"isSensitive": string;
|
||||
/**
|
||||
* この絵文字はリモートから見られないように設定されているため、リアクションできません。
|
||||
*/
|
||||
"localOnly": string;
|
||||
/**
|
||||
* この絵文字をリアクションとして使うにはロールが必要です。
|
||||
*/
|
||||
"roleIdsThatCanBeUsedThisEmojiAsReaction": string;
|
||||
};
|
||||
/**
|
||||
* 絵文字ピッカー
|
||||
*/
|
||||
|
|
|
@ -121,6 +121,11 @@ sensitive: "センシティブ"
|
|||
add: "追加"
|
||||
reaction: "リアクション"
|
||||
reactions: "リアクション"
|
||||
reactionDenied: "このリアクションをつける権限がありません。"
|
||||
_reactionDeniedReason:
|
||||
isSensitive: "投稿者がセンシティブなリアクションを許可していないため、リアクションできません。"
|
||||
localOnly: "この絵文字はリモートから見られないように設定されているため、リアクションできません。"
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: "この絵文字をリアクションとして使うにはロールが必要です。"
|
||||
emojiPicker: "絵文字ピッカー"
|
||||
pinnedEmojisForReactionSettingDescription: "リアクション時にピン留め表示する絵文字を設定できます"
|
||||
pinnedEmojisSettingDescription: "絵文字入力時にピン留め表示する絵文字を設定できます"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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', {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 };
|
||||
}
|
Loading…
Reference in New Issue