enhance: ユーザー検索を制限できるように (#16380)
* enhance: ユーザー検索を制限できるように * Update Changelog
This commit is contained in:
parent
7595bff43b
commit
b5b7914073
|
@ -17,6 +17,7 @@
|
||||||
- Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応
|
- Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応
|
||||||
- Enhance: acctに `.` が入っているユーザーのメンションに対応
|
- Enhance: acctに `.` が入っているユーザーのメンションに対応
|
||||||
- Fix: Unicode絵文字に隣接する異体字セレクタ(`U+FE0F`)が絵文字として認識される問題を修正
|
- Fix: Unicode絵文字に隣接する異体字セレクタ(`U+FE0F`)が絵文字として認識される問題を修正
|
||||||
|
- Enhance: ユーザー検索をロールポリシーで制限できるように
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Feat: AiScriptが1.0に更新されました
|
- Feat: AiScriptが1.0に更新されました
|
||||||
|
|
|
@ -4386,6 +4386,10 @@ export interface Locale extends ILocale {
|
||||||
* ノート検索は利用できません。
|
* ノート検索は利用できません。
|
||||||
*/
|
*/
|
||||||
"notesSearchNotAvailable": string;
|
"notesSearchNotAvailable": string;
|
||||||
|
/**
|
||||||
|
* ユーザー検索は利用できません。
|
||||||
|
*/
|
||||||
|
"usersSearchNotAvailable": string;
|
||||||
/**
|
/**
|
||||||
* ライセンス
|
* ライセンス
|
||||||
*/
|
*/
|
||||||
|
@ -7799,6 +7803,10 @@ export interface Locale extends ILocale {
|
||||||
* ノート検索の利用
|
* ノート検索の利用
|
||||||
*/
|
*/
|
||||||
"canSearchNotes": string;
|
"canSearchNotes": string;
|
||||||
|
/**
|
||||||
|
* ユーザー検索の利用
|
||||||
|
*/
|
||||||
|
"canSearchUsers": string;
|
||||||
/**
|
/**
|
||||||
* 翻訳機能の利用
|
* 翻訳機能の利用
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1092,6 +1092,7 @@ prohibitedWordsDescription2: "スペースで区切るとAND指定になり、
|
||||||
hiddenTags: "非表示ハッシュタグ"
|
hiddenTags: "非表示ハッシュタグ"
|
||||||
hiddenTagsDescription: "設定したタグをトレンドに表示させないようにします。改行で区切って複数設定できます。"
|
hiddenTagsDescription: "設定したタグをトレンドに表示させないようにします。改行で区切って複数設定できます。"
|
||||||
notesSearchNotAvailable: "ノート検索は利用できません。"
|
notesSearchNotAvailable: "ノート検索は利用できません。"
|
||||||
|
usersSearchNotAvailable: "ユーザー検索は利用できません。"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
unfavoriteConfirm: "お気に入り解除しますか?"
|
unfavoriteConfirm: "お気に入り解除しますか?"
|
||||||
myClips: "自分のクリップ"
|
myClips: "自分のクリップ"
|
||||||
|
@ -2020,6 +2021,7 @@ _role:
|
||||||
descriptionOfRateLimitFactor: "小さいほど制限が緩和され、大きいほど制限が強化されます。"
|
descriptionOfRateLimitFactor: "小さいほど制限が緩和され、大きいほど制限が強化されます。"
|
||||||
canHideAds: "広告の非表示"
|
canHideAds: "広告の非表示"
|
||||||
canSearchNotes: "ノート検索の利用"
|
canSearchNotes: "ノート検索の利用"
|
||||||
|
canSearchUsers: "ユーザー検索の利用"
|
||||||
canUseTranslator: "翻訳機能の利用"
|
canUseTranslator: "翻訳機能の利用"
|
||||||
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
||||||
canImportAntennas: "アンテナのインポートを許可"
|
canImportAntennas: "アンテナのインポートを許可"
|
||||||
|
|
|
@ -43,6 +43,7 @@ export type RolePolicies = {
|
||||||
canManageCustomEmojis: boolean;
|
canManageCustomEmojis: boolean;
|
||||||
canManageAvatarDecorations: boolean;
|
canManageAvatarDecorations: boolean;
|
||||||
canSearchNotes: boolean;
|
canSearchNotes: boolean;
|
||||||
|
canSearchUsers: boolean;
|
||||||
canUseTranslator: boolean;
|
canUseTranslator: boolean;
|
||||||
canHideAds: boolean;
|
canHideAds: boolean;
|
||||||
driveCapacityMb: number;
|
driveCapacityMb: number;
|
||||||
|
@ -82,6 +83,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
canManageCustomEmojis: false,
|
canManageCustomEmojis: false,
|
||||||
canManageAvatarDecorations: false,
|
canManageAvatarDecorations: false,
|
||||||
canSearchNotes: false,
|
canSearchNotes: false,
|
||||||
|
canSearchUsers: true,
|
||||||
canUseTranslator: true,
|
canUseTranslator: true,
|
||||||
canHideAds: false,
|
canHideAds: false,
|
||||||
driveCapacityMb: 100,
|
driveCapacityMb: 100,
|
||||||
|
@ -402,6 +404,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
|
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
|
||||||
canManageAvatarDecorations: calc('canManageAvatarDecorations', vs => vs.some(v => v === true)),
|
canManageAvatarDecorations: calc('canManageAvatarDecorations', vs => vs.some(v => v === true)),
|
||||||
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
|
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
|
||||||
|
canSearchUsers: calc('canSearchUsers', vs => vs.some(v => v === true)),
|
||||||
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
|
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
|
||||||
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
||||||
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
|
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
|
||||||
|
|
|
@ -212,6 +212,10 @@ export const packedRolePoliciesSchema = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
|
canSearchUsers: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
canUseTranslator: {
|
canUseTranslator: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -13,6 +13,7 @@ export const meta = {
|
||||||
tags: ['users'],
|
tags: ['users'],
|
||||||
|
|
||||||
requireCredential: false,
|
requireCredential: false,
|
||||||
|
requiredRolePolicy: 'canSearchUsers',
|
||||||
|
|
||||||
description: 'Search for users.',
|
description: 'Search for users.',
|
||||||
|
|
||||||
|
|
|
@ -346,6 +346,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canSearchUsers, 'canSearchUsers'])">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canSearchUsers }}</template>
|
||||||
|
<template #suffix>
|
||||||
|
<span v-if="role.policies.canSearchUsers.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||||
|
<span v-else>{{ role.policies.canSearchUsers.value ? i18n.ts.yes : i18n.ts.no }}</span>
|
||||||
|
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.canSearchUsers)"></i></span>
|
||||||
|
</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<MkSwitch v-model="role.policies.canSearchUsers.useDefault" :readonly="readonly">
|
||||||
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkSwitch v-model="role.policies.canSearchUsers.value" :disabled="role.policies.canSearchUsers.useDefault" :readonly="readonly">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkRange v-model="role.policies.canSearchUsers.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||||
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
|
</MkRange>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTranslator, 'canUseTranslator'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTranslator, 'canUseTranslator'])">
|
||||||
<template #label>{{ i18n.ts._role._options.canUseTranslator }}</template>
|
<template #label>{{ i18n.ts._role._options.canUseTranslator }}</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
|
|
|
@ -122,6 +122,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canSearchUsers, 'canSearchUsers'])">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canSearchUsers }}</template>
|
||||||
|
<template #suffix>{{ policies.canSearchUsers ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<MkSwitch v-model="policies.canSearchUsers">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTranslator, 'canUseTranslator'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTranslator, 'canUseTranslator'])">
|
||||||
<template #label>{{ i18n.ts._role._options.canUseTranslator }}</template>
|
<template #label>{{ i18n.ts._role._options.canUseTranslator }}</template>
|
||||||
<template #suffix>{{ policies.canUseTranslator ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canUseTranslator ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
|
|
@ -15,16 +15,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="tab === 'user'" class="_spacer" style="--MI_SPACER-w: 800px;">
|
<div v-else-if="tab === 'user'" class="_spacer" style="--MI_SPACER-w: 800px;">
|
||||||
<XUser v-bind="props"/>
|
<div v-if="usersSearchAvailable">
|
||||||
|
<XUser v-bind="props"/>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<MkInfo warn>{{ i18n.ts.usersSearchNotAvailable }}</MkInfo>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageWithHeader>
|
</PageWithHeader>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, ref, toRef } from 'vue';
|
import { computed, defineAsyncComponent, ref, toRef } from 'vue';
|
||||||
|
import { $i } from '@/i.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { notesSearchAvailable } from '@/utility/check-permissions.js';
|
import { notesSearchAvailable, usersSearchAvailable } from '@/utility/check-permissions.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
|
@ -17,3 +17,11 @@ export const notesSearchAvailable = (
|
||||||
export const canSearchNonLocalNotes = (
|
export const canSearchNonLocalNotes = (
|
||||||
instance.noteSearchableScope === 'global'
|
instance.noteSearchableScope === 'global'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const usersSearchAvailable = (
|
||||||
|
// FIXME: instance.policies would be null in Vitest
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
($i == null && instance.policies != null && instance.policies.canSearchUsers) ||
|
||||||
|
($i != null && $i.policies.canSearchUsers) ||
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
|
@ -5211,6 +5211,7 @@ export type components = {
|
||||||
canManageCustomEmojis: boolean;
|
canManageCustomEmojis: boolean;
|
||||||
canManageAvatarDecorations: boolean;
|
canManageAvatarDecorations: boolean;
|
||||||
canSearchNotes: boolean;
|
canSearchNotes: boolean;
|
||||||
|
canSearchUsers: boolean;
|
||||||
canUseTranslator: boolean;
|
canUseTranslator: boolean;
|
||||||
canHideAds: boolean;
|
canHideAds: boolean;
|
||||||
driveCapacityMb: number;
|
driveCapacityMb: number;
|
||||||
|
|
Loading…
Reference in New Issue