diff options
| author | かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> | 2024-10-13 20:21:25 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-13 20:21:25 +0900 |
| commit | 45d42b8641585cbe582e4c2a95e03ef511df00be (patch) | |
| tree | c9c68a5aa21852022da175f558372bec065ad3e2 /packages/frontend | |
| parent | :art: (diff) | |
| download | misskey-45d42b8641585cbe582e4c2a95e03ef511df00be.tar.gz misskey-45d42b8641585cbe582e4c2a95e03ef511df00be.tar.bz2 misskey-45d42b8641585cbe582e4c2a95e03ef511df00be.zip | |
feat: ユーザーの名前に禁止ワードを設定できるように (#14756)
* wip
* :art:
* Enhance: モデレーター以上は制限の影響を受けないように
* refactor
* better error handling
* fix
* Revert "better error handling"
This reverts commit 5670b29cfa18a3894d0c2abfe0e5ef862e3b9ffa.
* error handling
* エラーが出ないのを修正
* translation
* Update Changelog
* status code
* :v:
* モデレーター以上は影響ないことを明記
* :art:
* update changelog
* spdx
* Update update.ts
* refactor
* eliminate `screen name`
* remove untracked file
---------
Co-authored-by: KanariKanaru <93921745+kanarikanaru@users.noreply.github.com>
Diffstat (limited to 'packages/frontend')
| -rw-r--r-- | packages/frontend/src/components/MkUserSetupDialog.Profile.vue | 5 | ||||
| -rw-r--r-- | packages/frontend/src/os.ts | 8 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/moderation.vue | 24 | ||||
| -rw-r--r-- | packages/frontend/src/pages/settings/profile.vue | 11 | ||||
| -rw-r--r-- | packages/frontend/src/scripts/get-note-menu.ts | 11 |
5 files changed, 48 insertions, 11 deletions
diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue index 3194641cdb..7cb48f6afb 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue @@ -51,6 +51,11 @@ watch(name, () => { // 空文字列をnullにしたいので??は使うな // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing name: name.value || null, + }, undefined, { + '0b3f9f6a-2f4d-4b1f-9fb4-49d3a2fd7191': { + title: i18n.ts.yourNameContainsProhibitedWords, + text: i18n.ts.yourNameContainsProhibitedWordsDescription, + }, }); }); diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index 60e4218a48..4d41cf5bc0 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -10,6 +10,7 @@ import { EventEmitter } from 'eventemitter3'; import * as Misskey from 'misskey-js'; import type { ComponentProps as CP } from 'vue-component-type-helpers'; import type { Form, GetFormResultType } from '@/scripts/form.js'; +import type { MenuItem } from '@/types/menu.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; @@ -22,7 +23,6 @@ import MkPasswordDialog from '@/components/MkPasswordDialog.vue'; import MkEmojiPickerDialog from '@/components/MkEmojiPickerDialog.vue'; import MkPopupMenu from '@/components/MkPopupMenu.vue'; import MkContextMenu from '@/components/MkContextMenu.vue'; -import type { MenuItem } from '@/types/menu.js'; import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { pleaseLogin } from '@/scripts/please-login.js'; import { showMovedDialog } from '@/scripts/show-moved-dialog.js'; @@ -35,6 +35,7 @@ export const apiWithDialog = (<E extends keyof Misskey.Endpoints = keyof Misskey endpoint: E, data: P = {} as any, token?: string | null | undefined, + customErrors?: Record<string, { title?: string; text: string; }>, ) => { const promise = misskeyApi(endpoint, data, token); promiseDialog(promise, null, async (err) => { @@ -77,6 +78,9 @@ export const apiWithDialog = (<E extends keyof Misskey.Endpoints = keyof Misskey } else if (err.message.startsWith('Unexpected token')) { title = i18n.ts.gotInvalidResponseError; text = i18n.ts.gotInvalidResponseErrorDescription; + } else if (customErrors && customErrors[err.id] != null) { + title = customErrors[err.id].title; + text = customErrors[err.id].text; } alert({ type: 'error', @@ -86,7 +90,7 @@ export const apiWithDialog = (<E extends keyof Misskey.Endpoints = keyof Misskey }); return promise; -}) as typeof misskeyApi; +}); export function promiseDialog<T extends Promise<any>>( promise: T, diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue index 04d23b1358..5d8a581b2e 100644 --- a/packages/frontend/src/pages/admin/moderation.vue +++ b/packages/frontend/src/pages/admin/moderation.vue @@ -58,6 +58,18 @@ SPDX-License-Identifier: AGPL-3.0-only </MkFolder> <MkFolder> + <template #icon><i class="ti ti-user-x"></i></template> + <template #label>{{ i18n.ts.prohibitedWordsForNameOfUser }}</template> + + <div class="_gaps"> + <MkTextarea v-model="prohibitedWordsForNameOfUser"> + <template #caption>{{ i18n.ts.prohibitedWordsForNameOfUserDescription }}<br>{{ i18n.ts.prohibitedWordsDescription2 }}</template> + </MkTextarea> + <MkButton primary @click="save_prohibitedWordsForNameOfUser">{{ i18n.ts.save }}</MkButton> + </div> + </MkFolder> + + <MkFolder> <template #icon><i class="ti ti-eye-off"></i></template> <template #label>{{ i18n.ts.hiddenTags }}</template> @@ -131,6 +143,7 @@ const enableRegistration = ref<boolean>(false); const emailRequiredForSignup = ref<boolean>(false); const sensitiveWords = ref<string>(''); const prohibitedWords = ref<string>(''); +const prohibitedWordsForNameOfUser = ref<string>(''); const hiddenTags = ref<string>(''); const preservedUsernames = ref<string>(''); const blockedHosts = ref<string>(''); @@ -143,10 +156,11 @@ async function init() { emailRequiredForSignup.value = meta.emailRequiredForSignup; sensitiveWords.value = meta.sensitiveWords.join('\n'); prohibitedWords.value = meta.prohibitedWords.join('\n'); + prohibitedWordsForNameOfUser.value = meta.prohibitedWordsForNameOfUser.join('\n'); hiddenTags.value = meta.hiddenTags.join('\n'); preservedUsernames.value = meta.preservedUsernames.join('\n'); blockedHosts.value = meta.blockedHosts.join('\n'); - silencedHosts.value = meta.silencedHosts.join('\n'); + silencedHosts.value = meta.silencedHosts?.join('\n') ?? ''; mediaSilencedHosts.value = meta.mediaSilencedHosts.join('\n'); } @@ -190,6 +204,14 @@ function save_prohibitedWords() { }); } +function save_prohibitedWordsForNameOfUser() { + os.apiWithDialog('admin/update-meta', { + prohibitedWordsForNameOfUser: prohibitedWordsForNameOfUser.value.split('\n'), + }).then(() => { + fetchInstance(true); + }); +} + function save_hiddenTags() { os.apiWithDialog('admin/update-meta', { hiddenTags: hiddenTags.value.split('\n'), diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 0d61f8d851..561894d2b7 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -142,13 +142,17 @@ const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.d const reactionAcceptance = computed(defaultStore.makeGetterSetter('reactionAcceptance')); +function assertVaildLang(lang: string | null): lang is keyof typeof langmap { + return lang != null && lang in langmap; +} + const profile = reactive({ name: $i.name, description: $i.description, followedMessage: $i.followedMessage, location: $i.location, birthday: $i.birthday, - lang: $i.lang, + lang: assertVaildLang($i.lang) ? $i.lang : null, isBot: $i.isBot ?? false, isCat: $i.isCat ?? false, }); @@ -202,6 +206,11 @@ function save() { lang: profile.lang || null, isBot: !!profile.isBot, isCat: !!profile.isCat, + }, undefined, { + '0b3f9f6a-2f4d-4b1f-9fb4-49d3a2fd7191': { + title: i18n.ts.yourNameContainsProhibitedWords, + text: i18n.ts.yourNameContainsProhibitedWordsDescription, + }, }); globalEvents.emit('requestClearPageCache'); claimAchievement('profileFilled'); diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index 4ffa0ab94d..c1846b0589 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -245,13 +245,10 @@ export function getNoteMenu(props: { function togglePin(pin: boolean): void { os.apiWithDialog(pin ? 'i/pin' : 'i/unpin', { noteId: appearNote.id, - }, undefined, null, res => { - if (res.id === '72dab508-c64d-498f-8740-a8eec1ba385a') { - os.alert({ - type: 'error', - text: i18n.ts.pinLimitExceeded, - }); - } + }, undefined, { + '72dab508-c64d-498f-8740-a8eec1ba385a': { + text: i18n.ts.pinLimitExceeded, + }, }); } |