フロント側でもリアクション権限のチェックをするように
This commit is contained in:
parent
30b48df9d9
commit
84fc05d080
|
@ -500,6 +500,24 @@ export interface Locale extends ILocale {
|
||||||
* リアクション
|
* リアクション
|
||||||
*/
|
*/
|
||||||
"reactions": string;
|
"reactions": string;
|
||||||
|
/**
|
||||||
|
* このリアクションをつける権限がありません。
|
||||||
|
*/
|
||||||
|
"reactionDenied": string;
|
||||||
|
"_reactionDeniedReason": {
|
||||||
|
/**
|
||||||
|
* 投稿者がセンシティブなリアクションを許可していないため、リアクションできません。
|
||||||
|
*/
|
||||||
|
"isSensitive": string;
|
||||||
|
/**
|
||||||
|
* この絵文字はリモートから見られないように設定されているため、リアクションできません。
|
||||||
|
*/
|
||||||
|
"localOnly": string;
|
||||||
|
/**
|
||||||
|
* この絵文字をリアクションとして使うにはロールが必要です。
|
||||||
|
*/
|
||||||
|
"roleIdsThatCanBeUsedThisEmojiAsReaction": string;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* 絵文字ピッカー
|
* 絵文字ピッカー
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -121,6 +121,11 @@ sensitive: "センシティブ"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
reaction: "リアクション"
|
reaction: "リアクション"
|
||||||
reactions: "リアクション"
|
reactions: "リアクション"
|
||||||
|
reactionDenied: "このリアクションをつける権限がありません。"
|
||||||
|
_reactionDeniedReason:
|
||||||
|
isSensitive: "投稿者がセンシティブなリアクションを許可していないため、リアクションできません。"
|
||||||
|
localOnly: "この絵文字はリモートから見られないように設定されているため、リアクションできません。"
|
||||||
|
roleIdsThatCanBeUsedThisEmojiAsReaction: "この絵文字をリアクションとして使うにはロールが必要です。"
|
||||||
emojiPicker: "絵文字ピッカー"
|
emojiPicker: "絵文字ピッカー"
|
||||||
pinnedEmojisForReactionSettingDescription: "リアクション時にピン留め表示する絵文字を設定できます"
|
pinnedEmojisForReactionSettingDescription: "リアクション時にピン留め表示する絵文字を設定できます"
|
||||||
pinnedEmojisSettingDescription: "絵文字入力時にピン留め表示する絵文字を設定できます"
|
pinnedEmojisSettingDescription: "絵文字入力時にピン留め表示する絵文字を設定できます"
|
||||||
|
|
|
@ -193,6 +193,7 @@ import { MenuItem } from '@/types/menu.js';
|
||||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||||
import { shouldCollapsed } from '@/scripts/collapsed.js';
|
import { shouldCollapsed } from '@/scripts/collapsed.js';
|
||||||
|
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -380,7 +381,21 @@ function react(viaKeyboard = false): void {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
blur();
|
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');
|
sound.playMisskeySfx('reaction');
|
||||||
|
|
||||||
if (props.mock) {
|
if (props.mock) {
|
||||||
|
|
|
@ -228,6 +228,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkPagination, { type Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { type Paging } from '@/components/MkPagination.vue';
|
||||||
import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -385,7 +386,21 @@ function react(viaKeyboard = false): void {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
blur();
|
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');
|
sound.playMisskeySfx('reaction');
|
||||||
|
|
||||||
misskeyApi('notes/reactions/create', {
|
misskeyApi('notes/reactions/create', {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
reaction: string;
|
reaction: string;
|
||||||
|
@ -48,12 +49,30 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const buttonEl = shallowRef<HTMLElement>();
|
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() {
|
async function toggleReaction() {
|
||||||
if (!canToggle.value) return;
|
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;
|
const oldReaction = props.note.myReaction;
|
||||||
if (oldReaction) {
|
if (oldReaction) {
|
||||||
|
@ -101,7 +120,7 @@ async function toggleReaction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function menu(ev) {
|
async function menu(ev) {
|
||||||
if (!canToggle.value) return;
|
if (!canGetInfo.value) return;
|
||||||
if (!props.reaction.includes(':')) return;
|
if (!props.reaction.includes(':')) return;
|
||||||
os.popupMenu([{
|
os.popupMenu([{
|
||||||
text: i18n.ts.info,
|
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