From d2e22f90507a1920c15d0b997009f52067a2a828 Mon Sep 17 00:00:00 2001 From: おさむのひと <46447427+samunohito@users.noreply.github.com> Date: Tue, 14 Jan 2025 20:14:02 +0900 Subject: refactor: SystemWebhook/UserWebhookの配信処理呼び出し部分の改善 (#15035) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * UserWebhook側の対処 * SystemWebhook側の対処 * fix test --- packages/backend/src/core/NoteCreateService.ts | 33 ++++---------------------- 1 file changed, 4 insertions(+), 29 deletions(-) (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 56ddcefd7c..7624172468 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -614,14 +614,7 @@ export class NoteCreateService implements OnApplicationShutdown { this.roleService.addNoteToRoleTimeline(noteObj); - this.webhookService.getActiveWebhooks().then(webhooks => { - webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note')); - for (const webhook of webhooks) { - this.queueService.userWebhookDeliver(webhook, 'note', { - note: noteObj, - }); - } - }); + this.webhookService.enqueueUserWebhook(user.id, 'note', { note: noteObj }); const nm = new NotificationManager(this.mutingsRepository, this.notificationService, user, note); @@ -641,13 +634,7 @@ export class NoteCreateService implements OnApplicationShutdown { if (!isThreadMuted) { nm.push(data.reply.userId, 'reply'); this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj); - - const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply')); - for (const webhook of webhooks) { - this.queueService.userWebhookDeliver(webhook, 'reply', { - note: noteObj, - }); - } + this.webhookService.enqueueUserWebhook(data.reply.userId, 'reply', { note: noteObj }); } } } @@ -664,13 +651,7 @@ export class NoteCreateService implements OnApplicationShutdown { // Publish event if ((user.id !== data.renote.userId) && data.renote.userHost === null) { this.globalEventService.publishMainStream(data.renote.userId, 'renote', noteObj); - - const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote')); - for (const webhook of webhooks) { - this.queueService.userWebhookDeliver(webhook, 'renote', { - note: noteObj, - }); - } + this.webhookService.enqueueUserWebhook(data.renote.userId, 'renote', { note: noteObj }); } } @@ -796,13 +777,7 @@ export class NoteCreateService implements OnApplicationShutdown { }); this.globalEventService.publishMainStream(u.id, 'mention', detailPackedNote); - - const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention')); - for (const webhook of webhooks) { - this.queueService.userWebhookDeliver(webhook, 'mention', { - note: detailPackedNote, - }); - } + this.webhookService.enqueueUserWebhook(u.id, 'mention', { note: detailPackedNote }); // Create notification nm.push(u.id, 'mention'); -- cgit v1.2.3-freya From b16f5a781e2f65855c4fad8dc31a413701e55df8 Mon Sep 17 00:00:00 2001 From: おさむのひと <46447427+samunohito@users.noreply.github.com> Date: Sat, 18 Jan 2025 08:35:47 +0900 Subject: fix(backend): localOnlyなノートの時は配送処理そのものを起動しない (#15020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend): localOnlyなノートの時は配送処理そのものを起動しない * fix CHANGELOG.md * fix CHANGELOG.md --- CHANGELOG.md | 1 + packages/backend/src/core/NoteCreateService.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/CHANGELOG.md b/CHANGELOG.md index 109883195d..28bfe64ecd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ - Fix: `/api/pages/update`にて`name`を指定せずにリクエストするとエラーが発生する問題を修正 - Fix: AIセンシティブ判定が arm64 環境で動作しない問題を修正 - Fix: 非Misskey系のソフトウェアからHTML``タグを含むノートを受信した場合、MFMの読み仮名(ルビ)文法に変換して表示 +- Fix: 連合OFFで投稿されたノートに対する冗長な処理を抑止 ( #15018 ) ### Misskey.js - Feat: allow setting `binaryType` of WebSocket connection diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 7624172468..8a79908e82 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -658,7 +658,7 @@ export class NoteCreateService implements OnApplicationShutdown { nm.notify(); //#region AP deliver - if (this.userEntityService.isLocalUser(user)) { + if (!data.localOnly && this.userEntityService.isLocalUser(user)) { (async () => { const noteActivity = await this.renderNoteOrRenoteActivity(data, note); const dm = this.apDeliverManagerService.createDeliverManager(user, noteActivity); -- cgit v1.2.3-freya From feeaf26641e9c5c8343d4ae3a157792495ed9d6c Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Tue, 28 Jan 2025 00:29:27 -0500 Subject: fix lint errors in NoteCreateService & NoteEditService --- packages/backend/src/core/NoteCreateService.ts | 4 ++-- packages/backend/src/core/NoteEditService.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 3bfced1d80..f24c665659 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -486,10 +486,10 @@ export class NoteCreateService implements OnApplicationShutdown { // should really not happen, but better safe than sorry if (data.reply?.id === insert.id) { - throw new Error("A note can't reply to itself"); + throw new Error('A note can\'t reply to itself'); } if (data.renote?.id === insert.id) { - throw new Error("A note can't renote itself"); + throw new Error('A note can\'t renote itself'); } if (data.uri != null) insert.uri = data.uri; diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 453ad5d9d0..18912181d7 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -309,7 +309,7 @@ export class NoteEditService implements OnApplicationShutdown { if (this.isRenote(data)) { if (data.renote.id === oldnote.id) { - throw new Error("A note can't renote itself"); + throw new Error('A note can\'t renote itself'); } switch (data.renote.visibility) { -- cgit v1.2.3-freya From ea89348b62706c4f6fbeaf603fc73d1b9874e7d0 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Tue, 28 Jan 2025 01:47:03 -0500 Subject: add user-level "force content warning" moderation feature --- locales/index.d.ts | 8 + .../1738043621143-add_user_mandatoryCW.js | 11 + packages/backend/src/core/NoteCreateService.ts | 11 + packages/backend/src/core/NoteEditService.ts | 10 + packages/backend/src/models/User.ts | 9 + .../src/server/api/endpoints/admin/cw-user.ts | 53 ++ .../src/server/api/endpoints/admin/show-user.ts | 5 + packages/frontend/src/pages/admin-user.vue | 16 + packages/misskey-js/src/autogen/apiClientJSDoc.ts | 814 ++++++++++----------- packages/misskey-js/src/consts.ts | 1 + sharkey-locales/en-US.yml | 3 + 11 files changed, 534 insertions(+), 407 deletions(-) create mode 100644 packages/backend/migration/1738043621143-add_user_mandatoryCW.js create mode 100644 packages/backend/src/server/api/endpoints/admin/cw-user.ts (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/locales/index.d.ts b/locales/index.d.ts index 9624b48b42..65e8096403 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12089,6 +12089,14 @@ export interface Locale extends ILocale { * ID */ "id": string; + /** + * Force content warning + */ + "mandatoryCW": string; + /** + * Applies a content warning to all posts created by this user. If the post already has a CW, then this is appended to the end. + */ + "mandatoryCWDescription": string; } declare const locales: { [lang: string]: Locale; diff --git a/packages/backend/migration/1738043621143-add_user_mandatoryCW.js b/packages/backend/migration/1738043621143-add_user_mandatoryCW.js new file mode 100644 index 0000000000..dd05076dd2 --- /dev/null +++ b/packages/backend/migration/1738043621143-add_user_mandatoryCW.js @@ -0,0 +1,11 @@ +export class AddUserMandatoryCW1738043621143 { + name = 'AddUserCW1738043621143' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "mandatoryCW" text`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "mandatoryCW"`); + } +} diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index f24c665659..ecf711e011 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -234,6 +234,7 @@ export class NoteCreateService implements OnApplicationShutdown { host: MiUser['host']; isBot: MiUser['isBot']; noindex: MiUser['noindex']; + mandatoryCW: MiUser['mandatoryCW']; }, data: Option, silent = false): Promise { // チャンネル外にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) @@ -368,6 +369,15 @@ export class NoteCreateService implements OnApplicationShutdown { data.cw = null; } + // Apply mandatory CW, if applicable + if (user.mandatoryCW) { + if (data.cw) { + data.cw += `, ${user.mandatoryCW}`; + } else { + data.cw = user.mandatoryCW; + } + } + let tags = data.apHashtags; let emojis = data.apEmojis; let mentionedUsers = data.apMentions; @@ -441,6 +451,7 @@ export class NoteCreateService implements OnApplicationShutdown { host: MiUser['host']; isBot: MiUser['isBot']; noindex: MiUser['noindex']; + mandatoryCW: MiUser['mandatoryCW']; }, data: Option): Promise { return this.create(user, data, true); } diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 18912181d7..1f947aaffb 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -230,6 +230,7 @@ export class NoteEditService implements OnApplicationShutdown { host: MiUser['host']; isBot: MiUser['isBot']; noindex: MiUser['noindex']; + mandatoryCW: MiUser['mandatoryCW']; }, editid: MiNote['id'], data: Option, silent = false): Promise { if (!editid) { throw new Error('fail'); @@ -396,6 +397,15 @@ export class NoteEditService implements OnApplicationShutdown { data.cw = null; } + // Apply mandatory CW, if applicable + if (user.mandatoryCW) { + if (data.cw) { + data.cw += `, ${user.mandatoryCW}`; + } else { + data.cw = user.mandatoryCW; + } + } + let tags = data.apHashtags; let emojis = data.apEmojis; let mentionedUsers = data.apMentions; diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 3a825d36a7..8a3ad1003d 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -339,6 +339,15 @@ export class MiUser { }) public enableRss: boolean; + /** + * Specifies a Content Warning that should be forcibly applied to all notes by this user. + * If null (default), then no Content Warning is applied. + */ + @Column('text', { + nullable: true, + }) + public mandatoryCW: string | null; + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/server/api/endpoints/admin/cw-user.ts b/packages/backend/src/server/api/endpoints/admin/cw-user.ts new file mode 100644 index 0000000000..d48ca565a4 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/cw-user.ts @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { UsersRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { CacheService } from '@/core/CacheService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + kind: 'write:admin:cw-user', +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + cw: { type: 'string', nullable: true }, + }, + required: ['userId', 'cw'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.usersRepository) + private readonly usersRepository: UsersRepository, + + private readonly globalEventService: GlobalEventService, + ) { + super(meta, paramDef, async ps => { + const result = await this.usersRepository.update(ps.userId, { + // Collapse empty strings to null + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + mandatoryCW: ps.cw || null, + }); + + if (result.affected && result.affected < 1) { + throw new Error('No such user'); + } + + // Synchronize caches and other processes + this.globalEventService.publishInternalEvent('localUserUpdated', { id: ps.userId }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 669bffe2dc..0f0b0f8e7a 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -144,6 +144,10 @@ export const meta = { type: 'string', optional: false, nullable: false, }, + mandatoryCW: { + type: 'string', + optional: false, nullable: true, + }, signins: { type: 'array', optional: false, nullable: false, @@ -260,6 +264,7 @@ export default class extends Endpoint { // eslint- isHibernated: user.isHibernated, lastActiveDate: user.lastActiveDate ? user.lastActiveDate.toISOString() : null, moderationNote: profile.moderationNote ?? '', + mandatoryCW: user.mandatoryCW, signins, policies: await this.roleService.getUserPolicies(user.id), roles: await this.roleEntityService.packMany(roles, me), diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 11a34d34ef..e21db84334 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -83,6 +83,11 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.suspend }} {{ i18n.ts.markAsNSFW }} + + + + +
{{ i18n.ts.resetPassword }}
@@ -222,6 +227,7 @@ import { i18n } from '@/i18n.js'; import { iAmAdmin, $i, iAmModerator } from '@/account.js'; import MkRolePreview from '@/components/MkRolePreview.vue'; import MkPagination from '@/components/MkPagination.vue'; +import MkInput from '@/components/MkInput.vue'; const props = withDefaults(defineProps<{ userId: string; @@ -243,6 +249,7 @@ const approved = ref(false); const suspended = ref(false); const markedAsNSFW = ref(false); const moderationNote = ref(''); +const mandatoryCW = ref(null); const isSystem = computed(() => info.value?.isSystem ?? false); const filesPagination = { endpoint: 'admin/drive/files' as const, @@ -281,6 +288,15 @@ function createFetcher() { markedAsNSFW.value = info.value.alwaysMarkNsfw; suspended.value = info.value.isSuspended; moderationNote.value = info.value.moderationNote; + mandatoryCW.value = info.value.mandatoryCW; + + // These watch statements work because they're lazy-initialized. + // The watched values are already set, so they don't trigger any "change" just from refreshing the user. + + watch(mandatoryCW, async () => { + await os.apiWithDialog('admin/cw-user', { userId: props.userId, cw: mandatoryCW.value }); + refreshUser(); + }); watch(moderationNote, async () => { await misskeyApi('admin/update-user-note', { userId: user.value.id, text: moderationNote.value }); diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index f4120b3afc..5e47ad15ad 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -5,7 +5,7 @@ declare module '../api.js' { export interface APIClient { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* */ @@ -17,7 +17,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* */ @@ -29,7 +29,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* */ @@ -41,7 +41,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* */ @@ -53,7 +53,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* */ @@ -65,7 +65,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-user-reports* */ request( @@ -76,7 +76,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -87,7 +87,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:account* */ request( @@ -98,7 +98,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:account* */ request( @@ -109,7 +109,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:ad* */ request( @@ -120,7 +120,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:ad* */ request( @@ -131,7 +131,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:ad* */ request( @@ -142,7 +142,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:ad* */ request( @@ -153,7 +153,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* */ request( @@ -164,7 +164,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* */ request( @@ -175,7 +175,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:announcements* */ request( @@ -186,7 +186,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* */ request( @@ -197,7 +197,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:approve-user* */ request( @@ -208,7 +208,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* */ request( @@ -219,7 +219,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* */ request( @@ -230,7 +230,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:avatar-decorations* */ request( @@ -241,7 +241,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* */ request( @@ -252,7 +252,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:meta* */ request( @@ -263,7 +263,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:meta* */ request( @@ -274,7 +274,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:decline-user* */ request( @@ -285,7 +285,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:delete-account* */ request( @@ -296,7 +296,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:delete-all-files-of-a-user* */ request( @@ -307,7 +307,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:drive* */ request( @@ -318,7 +318,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:drive* */ request( @@ -329,7 +329,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:drive* */ request( @@ -340,7 +340,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:drive* */ request( @@ -351,7 +351,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -362,7 +362,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -373,7 +373,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -384,7 +384,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -395,7 +395,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -406,7 +406,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -418,7 +418,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ request( @@ -429,7 +429,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ request( @@ -440,7 +440,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -451,7 +451,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -462,7 +462,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -473,7 +473,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -484,7 +484,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ request( @@ -495,7 +495,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ request( @@ -506,7 +506,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ request( @@ -517,7 +517,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ request( @@ -528,7 +528,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ request( @@ -539,7 +539,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* */ request( @@ -550,7 +550,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:meta* */ request( @@ -561,7 +561,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:index-stats* */ request( @@ -572,7 +572,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:table-stats* */ request( @@ -583,7 +583,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:user-ips* */ request( @@ -594,7 +594,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes* */ request( @@ -605,7 +605,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:invite-codes* */ request( @@ -616,7 +616,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:meta* */ request( @@ -627,7 +627,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:nsfw-user* */ request( @@ -638,7 +638,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:promo* */ request( @@ -649,7 +649,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:queue* */ request( @@ -660,7 +660,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:queue* */ request( @@ -671,7 +671,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:queue* */ request( @@ -682,7 +682,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:queue* */ request( @@ -693,7 +693,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ request( @@ -704,7 +704,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:relays* */ request( @@ -715,7 +715,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:relays* */ request( @@ -726,7 +726,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:relays* */ request( @@ -737,7 +737,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:reset-password* */ request( @@ -748,7 +748,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* */ request( @@ -759,7 +759,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ request( @@ -770,7 +770,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ request( @@ -781,7 +781,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ request( @@ -792,7 +792,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:roles* */ request( @@ -803,7 +803,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:roles* */ request( @@ -814,7 +814,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ request( @@ -825,7 +825,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ request( @@ -836,7 +836,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ request( @@ -847,7 +847,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* / **Permission**: *read:admin:roles* */ request( @@ -858,7 +858,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:send-email* */ request( @@ -869,7 +869,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:server-info* */ request( @@ -880,7 +880,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:show-moderation-log* */ request( @@ -891,7 +891,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:show-user* */ request( @@ -902,7 +902,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:show-user* */ request( @@ -913,7 +913,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:silence-user* */ request( @@ -924,7 +924,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:suspend-user* */ request( @@ -935,7 +935,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* */ @@ -947,7 +947,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* */ @@ -959,7 +959,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* */ @@ -971,7 +971,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* */ @@ -983,7 +983,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *read:admin:system-webhook* */ @@ -995,7 +995,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* */ @@ -1007,7 +1007,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:unnsfw-user* */ request( @@ -1018,7 +1018,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-avatar* */ request( @@ -1029,7 +1029,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-banner* */ request( @@ -1040,7 +1040,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:unsilence-user* */ request( @@ -1051,7 +1051,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:unsuspend-user* */ request( @@ -1062,7 +1062,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* */ request( @@ -1073,7 +1073,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:meta* */ request( @@ -1084,7 +1084,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:admin:user-note* */ request( @@ -1095,7 +1095,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1106,7 +1106,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1117,7 +1117,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1128,7 +1128,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1139,7 +1139,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -1150,7 +1150,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -1161,7 +1161,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -1172,7 +1172,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1183,7 +1183,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:federation* */ request( @@ -1194,7 +1194,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -1205,7 +1205,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1216,7 +1216,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1227,7 +1227,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -1239,7 +1239,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1250,7 +1250,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1261,7 +1261,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1272,7 +1272,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:blocks* */ request( @@ -1283,7 +1283,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:blocks* */ request( @@ -1294,7 +1294,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:blocks* */ request( @@ -1305,7 +1305,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1316,7 +1316,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1327,7 +1327,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:channels* */ request( @@ -1338,7 +1338,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:channels* */ request( @@ -1349,7 +1349,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1360,7 +1360,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:channels* */ request( @@ -1371,7 +1371,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:channels* */ request( @@ -1382,7 +1382,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:channels* */ request( @@ -1393,7 +1393,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:channels* */ request( @@ -1404,7 +1404,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1415,7 +1415,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1426,7 +1426,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1437,7 +1437,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:channels* */ request( @@ -1448,7 +1448,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:channels* */ request( @@ -1459,7 +1459,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:channels* */ request( @@ -1470,7 +1470,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1481,7 +1481,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1492,7 +1492,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1503,7 +1503,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1514,7 +1514,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1525,7 +1525,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1536,7 +1536,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1547,7 +1547,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1558,7 +1558,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1569,7 +1569,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1580,7 +1580,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1591,7 +1591,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1602,7 +1602,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1613,7 +1613,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1624,7 +1624,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1635,7 +1635,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* */ request( @@ -1646,7 +1646,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -1657,7 +1657,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:clip-favorite* */ request( @@ -1668,7 +1668,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* / **Permission**: *read:account* */ request( @@ -1679,7 +1679,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1690,7 +1690,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* / **Permission**: *read:account* */ request( @@ -1701,7 +1701,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* */ request( @@ -1712,7 +1712,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -1723,7 +1723,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1734,7 +1734,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1745,7 +1745,7 @@ declare module '../api.js' { /** * Find the notes to which the given file is attached. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1756,7 +1756,7 @@ declare module '../api.js' { /** * Check if a given file exists. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1767,7 +1767,7 @@ declare module '../api.js' { /** * Upload a new drive file. - * + * * **Credential required**: *Yes* / **Permission**: *write:drive* */ request( @@ -1778,7 +1778,7 @@ declare module '../api.js' { /** * Delete an existing drive file. - * + * * **Credential required**: *Yes* / **Permission**: *write:drive* */ request( @@ -1789,7 +1789,7 @@ declare module '../api.js' { /** * Search for a drive file by the given parameters. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1800,7 +1800,7 @@ declare module '../api.js' { /** * Search for a drive file by a hash of the contents. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1811,7 +1811,7 @@ declare module '../api.js' { /** * Show the properties of a drive file. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1822,7 +1822,7 @@ declare module '../api.js' { /** * Update the properties of a drive file. - * + * * **Credential required**: *Yes* / **Permission**: *write:drive* */ request( @@ -1833,7 +1833,7 @@ declare module '../api.js' { /** * Request the server to download a new drive file from the specified URL. - * + * * **Credential required**: *Yes* / **Permission**: *write:drive* */ request( @@ -1844,7 +1844,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1855,7 +1855,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:drive* */ request( @@ -1866,7 +1866,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:drive* */ request( @@ -1877,7 +1877,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1888,7 +1888,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1899,7 +1899,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:drive* */ request( @@ -1910,7 +1910,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:drive* */ request( @@ -1921,7 +1921,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1932,7 +1932,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1943,7 +1943,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1954,7 +1954,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1965,7 +1965,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -1976,7 +1976,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -1988,7 +1988,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -1999,7 +1999,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -2010,7 +2010,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2021,7 +2021,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2032,7 +2032,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2043,7 +2043,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2054,7 +2054,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2065,7 +2065,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2077,7 +2077,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2088,7 +2088,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:flash* */ request( @@ -2099,7 +2099,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:flash* */ request( @@ -2110,7 +2110,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2121,7 +2121,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:flash-likes* */ request( @@ -2132,7 +2132,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:flash* */ request( @@ -2143,7 +2143,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:flash-likes* */ request( @@ -2154,7 +2154,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2165,7 +2165,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:flash-likes* */ request( @@ -2176,7 +2176,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:flash* */ request( @@ -2187,7 +2187,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2198,7 +2198,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2209,7 +2209,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2220,7 +2220,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2231,7 +2231,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2242,7 +2242,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:following* */ request( @@ -2253,7 +2253,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2264,7 +2264,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:following* */ request( @@ -2275,7 +2275,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2286,7 +2286,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:following* */ request( @@ -2297,7 +2297,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2308,7 +2308,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2319,7 +2319,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2330,7 +2330,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:gallery* */ request( @@ -2341,7 +2341,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:gallery* */ request( @@ -2352,7 +2352,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* */ request( @@ -2363,7 +2363,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2374,7 +2374,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* */ request( @@ -2385,7 +2385,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:gallery* */ request( @@ -2396,7 +2396,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2407,7 +2407,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2418,7 +2418,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2429,7 +2429,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2440,7 +2440,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2451,7 +2451,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2462,7 +2462,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -2473,7 +2473,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -2484,7 +2484,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2496,7 +2496,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2508,7 +2508,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2520,7 +2520,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2532,7 +2532,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2544,7 +2544,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2556,7 +2556,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2568,7 +2568,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2580,7 +2580,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2592,7 +2592,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2604,7 +2604,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2616,7 +2616,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -2627,7 +2627,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2639,7 +2639,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2651,7 +2651,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2663,7 +2663,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2675,7 +2675,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2687,7 +2687,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2699,7 +2699,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2711,7 +2711,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2723,7 +2723,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2735,7 +2735,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2747,7 +2747,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:favorites* */ request( @@ -2758,7 +2758,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:gallery-likes* */ request( @@ -2769,7 +2769,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:gallery* */ request( @@ -2780,7 +2780,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2792,7 +2792,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2804,7 +2804,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2816,7 +2816,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2828,7 +2828,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2840,7 +2840,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2852,7 +2852,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2864,7 +2864,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:notifications* */ request( @@ -2875,7 +2875,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:notifications* */ request( @@ -2886,7 +2886,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:page-likes* */ request( @@ -2897,7 +2897,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:pages* */ request( @@ -2908,7 +2908,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -2919,7 +2919,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -2930,7 +2930,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -2941,7 +2941,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -2953,7 +2953,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -2964,7 +2964,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -2975,7 +2975,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -2986,7 +2986,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -2997,7 +2997,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3008,7 +3008,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3019,7 +3019,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3030,7 +3030,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -3042,7 +3042,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3053,7 +3053,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -3065,7 +3065,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -3077,7 +3077,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3088,7 +3088,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3099,7 +3099,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -3111,7 +3111,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3122,7 +3122,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3133,7 +3133,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3144,7 +3144,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3155,7 +3155,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* / **Permission**: *read:account* */ @@ -3167,7 +3167,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3178,7 +3178,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:invite-codes* */ request( @@ -3189,7 +3189,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:invite-codes* */ request( @@ -3200,7 +3200,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:invite-codes* */ request( @@ -3211,7 +3211,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:invite-codes* */ request( @@ -3222,7 +3222,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3233,7 +3233,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -3245,7 +3245,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:mutes* */ request( @@ -3256,7 +3256,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:mutes* */ request( @@ -3267,7 +3267,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:mutes* */ request( @@ -3278,7 +3278,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3289,7 +3289,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3300,7 +3300,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3311,7 +3311,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3322,7 +3322,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3333,7 +3333,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3344,7 +3344,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notes* */ request( @@ -3355,7 +3355,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notes* */ request( @@ -3366,7 +3366,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notes* */ request( @@ -3377,7 +3377,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:favorites* */ request( @@ -3388,7 +3388,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:favorites* */ request( @@ -3399,7 +3399,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3410,7 +3410,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3421,7 +3421,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3432,7 +3432,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3443,7 +3443,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:reactions* */ request( @@ -3454,7 +3454,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3465,7 +3465,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3476,7 +3476,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3487,7 +3487,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:federation* */ request( @@ -3498,7 +3498,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:votes* */ request( @@ -3509,7 +3509,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3520,7 +3520,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:reactions* */ request( @@ -3531,7 +3531,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:reactions* */ request( @@ -3542,7 +3542,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3553,7 +3553,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3564,7 +3564,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notes-schedule* */ request( @@ -3575,7 +3575,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notes-schedule* */ request( @@ -3586,7 +3586,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:notes-schedule* */ request( @@ -3597,7 +3597,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3608,7 +3608,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3619,7 +3619,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3630,7 +3630,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3641,7 +3641,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3652,7 +3652,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3663,7 +3663,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3674,7 +3674,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3685,7 +3685,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notes* */ request( @@ -3696,7 +3696,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3707,7 +3707,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3718,7 +3718,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notifications* */ request( @@ -3729,7 +3729,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notifications* */ request( @@ -3740,7 +3740,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notifications* */ request( @@ -3751,7 +3751,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:notifications* */ request( @@ -3762,7 +3762,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -3774,7 +3774,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:pages* */ request( @@ -3785,7 +3785,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:pages* */ request( @@ -3796,7 +3796,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3807,7 +3807,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:page-likes* */ request( @@ -3818,7 +3818,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3829,7 +3829,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:page-likes* */ request( @@ -3840,7 +3840,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:pages* */ request( @@ -3851,7 +3851,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3862,7 +3862,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3873,7 +3873,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3884,7 +3884,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:mutes* */ request( @@ -3895,7 +3895,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:mutes* */ request( @@ -3906,7 +3906,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:mutes* */ request( @@ -3917,7 +3917,7 @@ declare module '../api.js' { /** * Request a users password to be reset. - * + * * **Credential required**: *No* */ request( @@ -3928,7 +3928,7 @@ declare module '../api.js' { /** * Only available when running with NODE_ENV=testing. Reset the database and flush Redis. - * + * * **Credential required**: *No* */ request( @@ -3939,7 +3939,7 @@ declare module '../api.js' { /** * Complete the password reset that was previously requested. - * + * * **Credential required**: *No* */ request( @@ -3950,7 +3950,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3961,7 +3961,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -3972,7 +3972,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -3983,7 +3983,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -3994,7 +3994,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4005,7 +4005,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4016,7 +4016,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4027,7 +4027,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4038,7 +4038,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -4049,7 +4049,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -4060,7 +4060,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4071,7 +4071,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4082,7 +4082,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4093,7 +4093,7 @@ declare module '../api.js' { /** * Get Sharkey Sponsors or Instance Sponsors - * + * * **Credential required**: *No* */ request( @@ -4104,7 +4104,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4115,7 +4115,7 @@ declare module '../api.js' { /** * Register to receive push notifications. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -4127,7 +4127,7 @@ declare module '../api.js' { /** * Check push notification registration exists. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -4139,7 +4139,7 @@ declare module '../api.js' { /** * Unregister from receiving push notifications. - * + * * **Credential required**: *No* */ request( @@ -4150,7 +4150,7 @@ declare module '../api.js' { /** * Update push notification registration. - * + * * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ @@ -4162,7 +4162,7 @@ declare module '../api.js' { /** * Endpoint for testing input validation. - * + * * **Credential required**: *No* */ request( @@ -4173,7 +4173,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4184,7 +4184,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4195,7 +4195,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4206,7 +4206,7 @@ declare module '../api.js' { /** * Show all clips this user owns. - * + * * **Credential required**: *No* */ request( @@ -4217,7 +4217,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4228,7 +4228,7 @@ declare module '../api.js' { /** * Show all flashs this user created. - * + * * **Credential required**: *No* */ request( @@ -4239,7 +4239,7 @@ declare module '../api.js' { /** * Show everyone that follows this user. - * + * * **Credential required**: *No* */ request( @@ -4250,7 +4250,7 @@ declare module '../api.js' { /** * Show everyone that this user is following. - * + * * **Credential required**: *No* */ request( @@ -4261,7 +4261,7 @@ declare module '../api.js' { /** * Show all gallery posts by the given user. - * + * * **Credential required**: *No* */ request( @@ -4272,7 +4272,7 @@ declare module '../api.js' { /** * Get a list of other users that the specified user frequently replies to. - * + * * **Credential required**: *No* */ request( @@ -4283,7 +4283,7 @@ declare module '../api.js' { /** * Create a new list of users. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4294,7 +4294,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4305,7 +4305,7 @@ declare module '../api.js' { /** * Delete an existing list of users. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4316,7 +4316,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4327,7 +4327,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* / **Permission**: *read:account* */ request( @@ -4338,7 +4338,7 @@ declare module '../api.js' { /** * Show all lists that the authenticated user has created. - * + * * **Credential required**: *No* / **Permission**: *read:account* */ request( @@ -4349,7 +4349,7 @@ declare module '../api.js' { /** * Remove a user from a list. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4360,7 +4360,7 @@ declare module '../api.js' { /** * Add a user to an existing list. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4371,7 +4371,7 @@ declare module '../api.js' { /** * Show the properties of a list. - * + * * **Credential required**: *No* / **Permission**: *read:account* */ request( @@ -4382,7 +4382,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4393,7 +4393,7 @@ declare module '../api.js' { /** * Update the properties of a list. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4404,7 +4404,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4415,7 +4415,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *No* */ request( @@ -4426,7 +4426,7 @@ declare module '../api.js' { /** * Show all pages this user created. - * + * * **Credential required**: *No* */ request( @@ -4437,7 +4437,7 @@ declare module '../api.js' { /** * Show all reactions this user made. - * + * * **Credential required**: *No* */ request( @@ -4448,7 +4448,7 @@ declare module '../api.js' { /** * Show users that the authenticated user might be interested to follow. - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -4459,7 +4459,7 @@ declare module '../api.js' { /** * Show the different kinds of relations between the authenticated user and the specified user(s). - * + * * **Credential required**: *Yes* / **Permission**: *read:account* */ request( @@ -4470,7 +4470,7 @@ declare module '../api.js' { /** * File a report. - * + * * **Credential required**: *Yes* / **Permission**: *write:report-abuse* */ request( @@ -4481,7 +4481,7 @@ declare module '../api.js' { /** * Search for users. - * + * * **Credential required**: *No* */ request( @@ -4492,7 +4492,7 @@ declare module '../api.js' { /** * Search for a user by username and/or host. - * + * * **Credential required**: *No* */ request( @@ -4503,7 +4503,7 @@ declare module '../api.js' { /** * Show the properties of a user. - * + * * **Credential required**: *No* */ request( @@ -4514,7 +4514,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *write:account* */ request( @@ -4525,7 +4525,7 @@ declare module '../api.js' { /** * No description provided. - * + * * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ request( diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index 0faf3dddc4..1d4950ceea 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -83,6 +83,7 @@ export const permissions = [ 'write:admin:decline-user', 'write:admin:nsfw-user', 'write:admin:unnsfw-user', + 'write:admin:cw-user', 'write:admin:silence-user', 'write:admin:unsilence-user', 'write:admin:unset-user-avatar', diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index 86eafc8a33..b95a912a5f 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -471,3 +471,6 @@ _noteSearch: flash: "Flash" id: "ID" + +mandatoryCW: "Force content warning" +mandatoryCWDescription: "Applies a content warning to all posts created by this user. If the post already has a CW, then this is appended to the end." -- cgit v1.2.3-freya From b256ac32d0c3ec3a3bd61589f1d70ee0dd6afa1f Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Tue, 28 Jan 2025 13:08:56 -0500 Subject: don't duplicate mandatory CWs --- packages/backend/src/core/NoteCreateService.ts | 6 +++--- packages/backend/src/core/NoteEditService.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index ecf711e011..10706f366d 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -371,10 +371,10 @@ export class NoteCreateService implements OnApplicationShutdown { // Apply mandatory CW, if applicable if (user.mandatoryCW) { - if (data.cw) { - data.cw += `, ${user.mandatoryCW}`; - } else { + if (!data.cw) { data.cw = user.mandatoryCW; + } else if (!data.cw.includes(user.mandatoryCW)) { + data.cw += `, ${user.mandatoryCW}`; } } diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 1f947aaffb..91d81c2965 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -399,10 +399,10 @@ export class NoteEditService implements OnApplicationShutdown { // Apply mandatory CW, if applicable if (user.mandatoryCW) { - if (data.cw) { - data.cw += `, ${user.mandatoryCW}`; - } else { + if (!data.cw) { data.cw = user.mandatoryCW; + } else if (!data.cw.includes(user.mandatoryCW)) { + data.cw += `, ${user.mandatoryCW}`; } } -- cgit v1.2.3-freya From 7814c6e54e18b02d30d0eebb7f0780e23a9e911e Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 12 Feb 2025 13:59:49 -0500 Subject: remove mandatory CW logic from NoteCreateService and NoteEditService --- packages/backend/src/core/NoteCreateService.ts | 17 +++-------------- packages/backend/src/core/NoteEditService.ts | 10 ---------- 2 files changed, 3 insertions(+), 24 deletions(-) (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 10706f366d..6564a64d30 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -234,7 +234,6 @@ export class NoteCreateService implements OnApplicationShutdown { host: MiUser['host']; isBot: MiUser['isBot']; noindex: MiUser['noindex']; - mandatoryCW: MiUser['mandatoryCW']; }, data: Option, silent = false): Promise { // チャンネル外にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) @@ -369,15 +368,6 @@ export class NoteCreateService implements OnApplicationShutdown { data.cw = null; } - // Apply mandatory CW, if applicable - if (user.mandatoryCW) { - if (!data.cw) { - data.cw = user.mandatoryCW; - } else if (!data.cw.includes(user.mandatoryCW)) { - data.cw += `, ${user.mandatoryCW}`; - } - } - let tags = data.apHashtags; let emojis = data.apEmojis; let mentionedUsers = data.apMentions; @@ -451,7 +441,6 @@ export class NoteCreateService implements OnApplicationShutdown { host: MiUser['host']; isBot: MiUser['isBot']; noindex: MiUser['noindex']; - mandatoryCW: MiUser['mandatoryCW']; }, data: Option): Promise { return this.create(user, data, true); } @@ -764,7 +753,7 @@ export class NoteCreateService implements OnApplicationShutdown { //#region AP deliver if (!data.localOnly && this.userEntityService.isLocalUser(user)) { (async () => { - const noteActivity = await this.renderNoteOrRenoteActivity(data, note); + const noteActivity = await this.renderNoteOrRenoteActivity(data, note, user); const dm = this.apDeliverManagerService.createDeliverManager(user, noteActivity); // メンションされたリモートユーザーに配送 @@ -910,12 +899,12 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - private async renderNoteOrRenoteActivity(data: Option, note: MiNote) { + private async renderNoteOrRenoteActivity(data: Option, note: MiNote, user: MiUser) { if (data.localOnly) return null; const content = this.isRenote(data) && !this.isQuote(data) ? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note) - : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note); + : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, user, false), note); return this.apRendererService.addContext(content); } diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 91d81c2965..18912181d7 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -230,7 +230,6 @@ export class NoteEditService implements OnApplicationShutdown { host: MiUser['host']; isBot: MiUser['isBot']; noindex: MiUser['noindex']; - mandatoryCW: MiUser['mandatoryCW']; }, editid: MiNote['id'], data: Option, silent = false): Promise { if (!editid) { throw new Error('fail'); @@ -397,15 +396,6 @@ export class NoteEditService implements OnApplicationShutdown { data.cw = null; } - // Apply mandatory CW, if applicable - if (user.mandatoryCW) { - if (!data.cw) { - data.cw = user.mandatoryCW; - } else if (!data.cw.includes(user.mandatoryCW)) { - data.cw += `, ${user.mandatoryCW}`; - } - } - let tags = data.apHashtags; let emojis = data.apEmojis; let mentionedUsers = data.apMentions; -- cgit v1.2.3-freya From 5c86929b584d799c33b8a75f1129c347167c444f Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 12 Feb 2025 15:12:15 -0500 Subject: fix type errors in NoteCreateService.ts --- packages/backend/src/core/NoteCreateService.ts | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 6564a64d30..71c0c0a55d 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -228,13 +228,7 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - public async create(user: { - id: MiUser['id']; - username: MiUser['username']; - host: MiUser['host']; - isBot: MiUser['isBot']; - noindex: MiUser['noindex']; - }, data: Option, silent = false): Promise { + public async create(user: MiUser, data: Option, silent = false): Promise { // チャンネル外にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { @@ -435,13 +429,7 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - public async import(user: { - id: MiUser['id']; - username: MiUser['username']; - host: MiUser['host']; - isBot: MiUser['isBot']; - noindex: MiUser['noindex']; - }, data: Option): Promise { + public async import(user: MiUser, data: Option): Promise { return this.create(user, data, true); } @@ -552,13 +540,7 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - private async postNoteCreated(note: MiNote, user: { - id: MiUser['id']; - username: MiUser['username']; - host: MiUser['host']; - isBot: MiUser['isBot']; - noindex: MiUser['noindex']; - }, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { + private async postNoteCreated(note: MiNote, user: MiUser, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { this.notesChart.update(note, true); if (note.visibility !== 'specified' && (this.meta.enableChartsForRemoteUser || (user.host == null))) { this.perUserNotesChart.update(user, note, true); -- cgit v1.2.3-freya From 86b26fb58ea8264523f468131cd87d0a43aea9fe Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Sat, 15 Feb 2025 11:39:57 -0500 Subject: adjust types to avoid merge conflicts in NoteCreateService.ts and NoteEditService.ts --- packages/backend/src/core/NoteCreateService.ts | 24 +++++++++++++++++++++--- packages/backend/src/core/NoteEditService.ts | 16 ++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 71c0c0a55d..8291db9b42 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -228,7 +228,13 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - public async create(user: MiUser, data: Option, silent = false): Promise { + public async create(user: MiUser & { + id: MiUser['id']; + username: MiUser['username']; + host: MiUser['host']; + isBot: MiUser['isBot']; + noindex: MiUser['noindex']; + }, data: Option, silent = false): Promise { // チャンネル外にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { @@ -429,7 +435,13 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - public async import(user: MiUser, data: Option): Promise { + public async import(user: MiUser & { + id: MiUser['id']; + username: MiUser['username']; + host: MiUser['host']; + isBot: MiUser['isBot']; + noindex: MiUser['noindex']; + }, data: Option): Promise { return this.create(user, data, true); } @@ -540,7 +552,13 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - private async postNoteCreated(note: MiNote, user: MiUser, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { + private async postNoteCreated(note: MiNote, user: MiUser & { + id: MiUser['id']; + username: MiUser['username']; + host: MiUser['host']; + isBot: MiUser['isBot']; + noindex: MiUser['noindex']; + }, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { this.notesChart.update(note, true); if (note.visibility !== 'specified' && (this.meta.enableChartsForRemoteUser || (user.host == null))) { this.perUserNotesChart.update(user, note, true); diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 854112ec1d..24a99156d2 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -224,7 +224,13 @@ export class NoteEditService implements OnApplicationShutdown { } @bindThis - public async edit(user: MiUser, editid: MiNote['id'], data: Option, silent = false): Promise { + public async edit(user: MiUser & { + id: MiUser['id']; + username: MiUser['username']; + host: MiUser['host']; + isBot: MiUser['isBot']; + noindex: MiUser['noindex']; + }, editid: MiNote['id'], data: Option, silent = false): Promise { if (!editid) { throw new Error('fail'); } @@ -578,7 +584,13 @@ export class NoteEditService implements OnApplicationShutdown { } @bindThis - private async postNoteEdited(note: MiNote, oldNote: MiNote, user: MiUser, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { + private async postNoteEdited(note: MiNote, oldNote: MiNote, user: MiUser & { + id: MiUser['id']; + username: MiUser['username']; + host: MiUser['host']; + isBot: MiUser['isBot']; + noindex: MiUser['noindex']; + }, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { // Register host if (this.meta.enableStatsForFederatedInstances) { if (this.userEntityService.isRemoteUser(user)) { -- cgit v1.2.3-freya From 292d3b92295d194856cb73c66ac097180f70deb8 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Sat, 15 Feb 2025 23:08:02 -0500 Subject: add "reject quotes" toggle at user and instance level + improve, cleanup, and de-duplicate quote resolution + add warning message when quote cannot be loaded + add "process error" framework to display warnings when a note cannot be correctly loaded from another instance --- locales/index.d.ts | 34 +++++ .../1739671352784-add_note_processErrors.js | 11 ++ .../1739671777344-add_user_rejectQuotes.js | 11 ++ .../1739671847942-add_instance_rejectQuotes.js | 11 ++ packages/backend/src/core/NoteCreateService.ts | 30 +++++ packages/backend/src/core/NoteEditService.ts | 5 + .../src/core/activitypub/models/ApNoteService.ts | 143 ++++++++++----------- .../src/core/entities/InstanceEntityService.ts | 1 + .../backend/src/core/entities/NoteEntityService.ts | 1 + .../backend/src/core/entities/UserEntityService.ts | 1 + packages/backend/src/models/Instance.ts | 9 ++ packages/backend/src/models/Note.ts | 11 ++ packages/backend/src/models/User.ts | 9 ++ .../src/models/json-schema/federation-instance.ts | 5 + packages/backend/src/models/json-schema/note.ts | 8 ++ packages/backend/src/models/json-schema/user.ts | 4 + .../endpoints/admin/federation/update-instance.ts | 10 ++ .../server/api/endpoints/admin/reject-quotes.ts | 63 +++++++++ .../src/server/api/endpoints/notes/create.ts | 8 ++ .../backend/src/server/api/endpoints/notes/edit.ts | 8 ++ packages/backend/src/types.ts | 22 ++++ packages/frontend/src/components/MkNote.vue | 2 +- .../frontend/src/components/MkNoteDetailed.vue | 2 +- packages/frontend/src/components/MkNoteSub.vue | 2 +- packages/frontend/src/components/MkPostForm.vue | 2 +- packages/frontend/src/components/SkErrorList.vue | 43 +++++++ packages/frontend/src/components/SkNote.vue | 2 +- .../frontend/src/components/SkNoteDetailed.vue | 2 +- packages/frontend/src/components/SkNoteSub.vue | 2 +- packages/frontend/src/pages/admin-user.vue | 19 +++ .../frontend/src/pages/admin/modlog.ModLog.vue | 12 ++ packages/frontend/src/pages/instance-info.vue | 12 ++ packages/frontend/src/pages/note.vue | 8 +- packages/misskey-js/src/consts.ts | 19 +++ packages/misskey-js/src/entities.ts | 12 ++ sharkey-locales/en-US.yml | 10 ++ 36 files changed, 466 insertions(+), 88 deletions(-) create mode 100644 packages/backend/migration/1739671352784-add_note_processErrors.js create mode 100644 packages/backend/migration/1739671777344-add_user_rejectQuotes.js create mode 100644 packages/backend/migration/1739671847942-add_instance_rejectQuotes.js create mode 100644 packages/backend/src/server/api/endpoints/admin/reject-quotes.ts create mode 100644 packages/frontend/src/components/SkErrorList.vue (limited to 'packages/backend/src/core/NoteCreateService.ts') diff --git a/locales/index.d.ts b/locales/index.d.ts index bf49869bf8..cc7884b8c1 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -8566,6 +8566,10 @@ export interface Locale extends ILocale { * Un-silence users */ "write:admin:unsilence-user": string; + /** + * Allow/Reject quote posts from a user + */ + "write:admin:reject-quotes": string; /** * View your list of scheduled notes */ @@ -10242,6 +10246,14 @@ export interface Locale extends ILocale { * Accepted reports from remote instance */ "acceptRemoteInstanceReports": string; + /** + * Rejected quotes from user + */ + "rejectQuotesUser": string; + /** + * Allowed quotes from user + */ + "allowQuotesUser": string; }; "_fileViewer": { /** @@ -11240,6 +11252,22 @@ export interface Locale extends ILocale { * Reject reports from this instance */ "rejectReports": string; + /** + * Reject quote posts from this instance + */ + "rejectQuotesInstance": string; + /** + * Reject quote posts from this user + */ + "rejectQuotesUser": string; + /** + * Are you sure you wish to reject quote posts? + */ + "rejectQuotesConfirm": string; + /** + * Are you sure you wish to allow quote posts? + */ + "allowQuotesConfirm": string; /** * This host is blocked implicitly because a base domain is blocked. To unblock this host, first unblock the base domain(s). */ @@ -12109,6 +12137,12 @@ export interface Locale extends ILocale { * Applies a content warning to all posts created by this user. If the post already has a CW, then this is appended to the end. */ "mandatoryCWDescription": string; + "_processErrors": { + /** + * Unable to process quote. This post may be missing context. + */ + "quoteUnavailable": string; + }; } declare const locales: { [lang: string]: Locale; diff --git a/packages/backend/migration/1739671352784-add_note_processErrors.js b/packages/backend/migration/1739671352784-add_note_processErrors.js new file mode 100644 index 0000000000..0be10125e1 --- /dev/null +++ b/packages/backend/migration/1739671352784-add_note_processErrors.js @@ -0,0 +1,11 @@ +export class AddNoteProcessErrors1739671352784 { + name = 'AddNoteProcessErrors1739671352784' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "note" ADD "processErrors" text array`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "processErrors"`); + } +} diff --git a/packages/backend/migration/1739671777344-add_user_rejectQuotes.js b/packages/backend/migration/1739671777344-add_user_rejectQuotes.js new file mode 100644 index 0000000000..29ed90c8ff --- /dev/null +++ b/packages/backend/migration/1739671777344-add_user_rejectQuotes.js @@ -0,0 +1,11 @@ +export class AddUserRejectQuotes1739671777344 { + name = 'AddUserRejectQuotes1739671777344' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "rejectQuotes" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "rejectQuotes"`); + } +} diff --git a/packages/backend/migration/1739671847942-add_instance_rejectQuotes.js b/packages/backend/migration/1739671847942-add_instance_rejectQuotes.js new file mode 100644 index 0000000000..89774eb991 --- /dev/null +++ b/packages/backend/migration/1739671847942-add_instance_rejectQuotes.js @@ -0,0 +1,11 @@ +export class AddInstanceRejectQuotes1739671847942 { + name = 'AddInstanceRejectQuotes1739671847942' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" ADD "rejectQuotes" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "rejectQuotes"`); + } +} diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 8291db9b42..df31cb4247 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -144,6 +144,7 @@ type Option = { uri?: string | null; url?: string | null; app?: MiApp | null; + processErrors?: string[] | null; }; export type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] }); @@ -309,6 +310,9 @@ export class NoteCreateService implements OnApplicationShutdown { } } + // Check quote permissions + await this.checkQuotePermissions(data, user); + // Check blocking if (this.isRenote(data) && !this.isQuote(data)) { if (data.renote.userHost === null) { @@ -482,6 +486,7 @@ export class NoteCreateService implements OnApplicationShutdown { renoteUserId: data.renote ? data.renote.userId : null, renoteUserHost: data.renote ? data.renote.userHost : null, userHost: user.host, + processErrors: data.processErrors, }); // should really not happen, but better safe than sorry @@ -1147,4 +1152,29 @@ export class NoteCreateService implements OnApplicationShutdown { public async onApplicationShutdown(signal?: string | undefined): Promise { await this.dispose(); } + + @bindThis + public async checkQuotePermissions(data: Option, user: MiUser): Promise { + // Not a quote + if (!this.isRenote(data) || !this.isQuote(data)) return; + + // User cannot quote + if (user.rejectQuotes) { + if (user.host == null) { + throw new IdentifiableError('1c0ea108-d1e3-4e8e-aa3f-4d2487626153', 'QUOTE_DISABLED_FOR_USER'); + } else { + (data as Option).renote = null; + (data.processErrors ??= []).push('quoteUnavailable'); + } + } + + // Instance cannot quote + if (user.host) { + const instance = await this.federatedInstanceService.fetch(user.host); + if (instance?.rejectQuotes) { + (data as Option).renote = null; + (data.processErrors ??= []).push('quoteUnavailable'); + } + } + } } diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 24a99156d2..7851af86b7 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -140,6 +140,7 @@ type Option = { app?: MiApp | null; updatedAt?: Date | null; editcount?: boolean | null; + processErrors?: string[] | null; }; @Injectable() @@ -337,6 +338,9 @@ export class NoteEditService implements OnApplicationShutdown { } } + // Check quote permissions + await this.noteCreateService.checkQuotePermissions(data, user); + // Check blocking if (this.isRenote(data) && !this.isQuote(data)) { if (data.renote.userHost === null) { @@ -529,6 +533,7 @@ export class NoteEditService implements OnApplicationShutdown { if (data.uri != null) note.uri = data.uri; if (data.url != null) note.url = data.url; + if (data.processErrors !== undefined) note.processErrors = data.processErrors; if (mentionedUsers.length > 0) { note.mentions = mentionedUsers.map(u => u.id); diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index 2995b1e764..8470285e93 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -296,44 +296,8 @@ export class ApNoteService { : null; // 引用 - let quote: MiNote | undefined | null = null; - - if (note._misskey_quote ?? note.quoteUrl ?? note.quoteUri) { - const tryResolveNote = async (uri: unknown): Promise< - | { status: 'ok'; res: MiNote } - | { status: 'permerror' | 'temperror' } - > => { - if (typeof uri !== 'string' || !/^https?:/.test(uri)) { - this.logger.warn(`Failed to resolve quote ${uri} for note ${entryUri}: URI is invalid`); - return { status: 'permerror' }; - } - try { - const res = await this.resolveNote(uri, { resolver }); - if (res == null) { - this.logger.warn(`Failed to resolve quote ${uri} for note ${entryUri}: resolution error`); - return { status: 'permerror' }; - } - return { status: 'ok', res }; - } catch (e) { - const error = e instanceof Error ? `${e.name}: ${e.message}` : String(e); - this.logger.warn(`Failed to resolve quote ${uri} for note ${entryUri}: ${error}`); - - return { - status: (e instanceof StatusError && !e.isRetryable) ? 'permerror' : 'temperror', - }; - } - }; - - const uris = unique([note._misskey_quote, note.quoteUrl, note.quoteUri].filter(x => x != null)); - const results = await Promise.all(uris.map(tryResolveNote)); - - quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0); - if (!quote) { - if (results.some(x => x.status === 'temperror')) { - throw new Error(`temporary error resolving quote for ${entryUri}`); - } - } - } + const quote = await this.getQuote(note, entryUri, resolver); + const processErrors = quote === null ? ['quoteUnavailable'] : null; // vote if (reply && reply.hasPoll) { @@ -369,7 +333,8 @@ export class ApNoteService { createdAt: note.published ? new Date(note.published) : null, files, reply, - renote: quote, + renote: quote ?? null, + processErrors, name: note.name, cw, text, @@ -538,44 +503,8 @@ export class ApNoteService { : null; // 引用 - let quote: MiNote | undefined | null = null; - - if (note._misskey_quote ?? note.quoteUrl ?? note.quoteUri) { - const tryResolveNote = async (uri: unknown): Promise< - | { status: 'ok'; res: MiNote } - | { status: 'permerror' | 'temperror' } - > => { - if (typeof uri !== 'string' || !/^https?:/.test(uri)) { - this.logger.warn(`Failed to resolve quote ${uri} for note ${entryUri}: URI is invalid`); - return { status: 'permerror' }; - } - try { - const res = await this.resolveNote(uri, { resolver }); - if (res == null) { - this.logger.warn(`Failed to resolve quote ${uri} for note ${entryUri}: resolution error`); - return { status: 'permerror' }; - } - return { status: 'ok', res }; - } catch (e) { - const error = e instanceof Error ? `${e.name}: ${e.message}` : String(e); - this.logger.warn(`Failed to resolve quote ${uri} for note ${entryUri}: ${error}`); - - return { - status: (e instanceof StatusError && !e.isRetryable) ? 'permerror' : 'temperror', - }; - } - }; - - const uris = unique([note._misskey_quote, note.quoteUrl, note.quoteUri].filter(x => x != null)); - const results = await Promise.all(uris.map(tryResolveNote)); - - quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0); - if (!quote) { - if (results.some(x => x.status === 'temperror')) { - throw new Error(`temporary error resolving quote for ${entryUri}`); - } - } - } + const quote = await this.getQuote(note, entryUri, resolver); + const processErrors = quote === null ? ['quoteUnavailable'] : null; // vote if (reply && reply.hasPoll) { @@ -611,7 +540,8 @@ export class ApNoteService { createdAt: note.published ? new Date(note.published) : null, files, reply, - renote: quote, + renote: quote ?? null, + processErrors, name: note.name, cw, text, @@ -734,6 +664,63 @@ export class ApNoteService { }); })); } + + /** + * Fetches the note's quoted post. + * On success - returns the note. + * On skip (no quote) - returns undefined. + * On permanent error - returns null. + * On temporary error - throws an exception. + */ + private async getQuote(note: IPost, entryUri: string, resolver: Resolver): Promise { + const quoteUris = new Set(); + if (note._misskey_quote) quoteUris.add(note._misskey_quote); + if (note.quoteUrl) quoteUris.add(note.quoteUrl); + if (note.quoteUri) quoteUris.add(note.quoteUri); + + // No quote, return undefined + if (quoteUris.size < 1) return undefined; + + /** + * Attempts to resolve a quote by URI. + * Returns the note if successful, true if there's a retryable error, and false if there's a permanent error. + */ + const resolveQuote = async (uri: unknown): Promise => { + if (typeof(uri) !== 'string' || !/^https?:/.test(uri)) { + this.logger.warn(`Failed to resolve quote "${uri}" for note "${entryUri}": URI is invalid`); + return false; + } + + try { + const quote = await this.resolveNote(uri, { resolver }); + + if (quote == null) { + this.logger.warn(`Failed to resolve quote "${uri}" for note "${entryUri}": request error`); + return false; + } + + return quote; + } catch (e) { + const error = e instanceof Error ? `${e.name}: ${e.message}` : String(e); + this.logger.warn(`Failed to resolve quote "${uri}" for note "${entryUri}": ${error}`); + + return (e instanceof StatusError && e.isRetryable); + } + }; + + const results = await Promise.all(Array.from(quoteUris).map(u => resolveQuote(u))); + + // Success - return the quote + const quote = results.find(r => typeof(r) === 'object'); + if (quote) return quote; + + // Temporary / retryable error - throw error + const tempError = results.find(r => r === true); + if (tempError) throw new Error(`temporary error resolving quote for "${entryUri}"`); + + // Permanent error - return null + return null; + } } function getBestIcon(note: IObject): IObject | null { diff --git a/packages/backend/src/core/entities/InstanceEntityService.ts b/packages/backend/src/core/entities/InstanceEntityService.ts index 63e5923255..fcc9bed3bd 100644 --- a/packages/backend/src/core/entities/InstanceEntityService.ts +++ b/packages/backend/src/core/entities/InstanceEntityService.ts @@ -60,6 +60,7 @@ export class InstanceEntityService { latestRequestReceivedAt: instance.latestRequestReceivedAt ? instance.latestRequestReceivedAt.toISOString() : null, isNSFW: instance.isNSFW, rejectReports: instance.rejectReports, + rejectQuotes: instance.rejectQuotes, moderationNote: iAmModerator ? instance.moderationNote : null, }; } diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index dca73567cc..1c51aba09b 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -490,6 +490,7 @@ export class NoteEntityService implements OnModuleInit { ...(opts.detail ? { clippedCount: note.clippedCount, + processErrors: note.processErrors, reply: note.replyId ? this.pack(note.reply ?? note.replyId, me, { detail: false, diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 4fbbbdd379..5d539ea264 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -674,6 +674,7 @@ export class UserEntityService implements OnModuleInit { securityKeys: profile!.twoFactorEnabled ? this.userSecurityKeysRepository.countBy({ userId: user.id }).then(result => result >= 1) : false, + rejectQuotes: user.rejectQuotes, } : {}), ...(isDetailed && isMe ? { diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts index ba93190c57..c64ebb1b3b 100644 --- a/packages/backend/src/models/Instance.ts +++ b/packages/backend/src/models/Instance.ts @@ -164,6 +164,15 @@ export class MiInstance { }) public rejectReports: boolean; + /** + * If true, quote posts from this instance will be downgraded to normal posts. + * The quote will be stripped and a process error will be generated. + */ + @Column('boolean', { + default: false, + }) + public rejectQuotes: boolean; + @Column('varchar', { length: 16384, default: '', }) diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts index 8b5265e8fe..2dabb75d83 100644 --- a/packages/backend/src/models/Note.ts +++ b/packages/backend/src/models/Note.ts @@ -203,6 +203,17 @@ export class MiNote { @JoinColumn() public channel: MiChannel | null; + /** + * List of non-fatal errors encountered while processing (creating or updating) this note. + * Entries can be a translation key (which will be queried from the "_processErrors" section) or a raw string. + * Errors will be displayed to the user when viewing the note. + */ + @Column('text', { + array: true, + nullable: true, + }) + public processErrors: string[] | null; + //#region Denormalized fields @Index() @Column('varchar', { diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 8a3ad1003d..5d87c7fa12 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -348,6 +348,15 @@ export class MiUser { }) public mandatoryCW: string | null; + /** + * If true, quote posts from this user will be downgraded to normal posts. + * The quote will be stripped and a process error will be generated. + */ + @Column('boolean', { + default: false, + }) + public rejectQuotes: boolean; + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/json-schema/federation-instance.ts b/packages/backend/src/models/json-schema/federation-instance.ts index 7960e748e9..57d4466ffa 100644 --- a/packages/backend/src/models/json-schema/federation-instance.ts +++ b/packages/backend/src/models/json-schema/federation-instance.ts @@ -126,6 +126,11 @@ export const packedFederationInstanceSchema = { optional: false, nullable: false, }, + rejectQuotes: { + type: 'boolean', + optional: false, + nullable: false, + }, moderationNote: { type: 'string', optional: true, nullable: true, diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index 432c096e48..51d23fe5e7 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -256,6 +256,14 @@ export const packedNoteSchema = { type: 'number', optional: true, nullable: false, }, + processErrors: { + type: 'array', + optional: true, nullable: true, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, myReaction: { type: 'string', diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 1c2ba538c1..3d0bf44c2e 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -445,6 +445,10 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: true, }, + rejectQuotes: { + type: 'boolean', + nullable: false, optional: true, + }, //#region relations isFollowing: { type: 'boolean', diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index daf19c4435..24d0b8527c 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -27,6 +27,7 @@ export const paramDef = { isNSFW: { type: 'boolean' }, rejectReports: { type: 'boolean' }, moderationNote: { type: 'string' }, + rejectQuotes: { type: 'boolean' }, }, required: ['host'], } as const; @@ -59,6 +60,7 @@ export default class extends Endpoint { // eslint- suspensionState, isNSFW: ps.isNSFW, rejectReports: ps.rejectReports, + rejectQuotes: ps.rejectQuotes, moderationNote: ps.moderationNote, }); @@ -92,6 +94,14 @@ export default class extends Endpoint { // eslint- }); } + if (ps.rejectQuotes != null && instance.rejectQuotes !== ps.rejectQuotes) { + const message = ps.rejectReports ? 'rejectQuotesInstance' : 'acceptQuotesInstance'; + this.moderationLogService.log(me, message, { + id: instance.id, + host: instance.host, + }); + } + if (ps.moderationNote != null && instance.moderationNote !== ps.moderationNote) { this.moderationLogService.log(me, 'updateRemoteInstanceNote', { id: instance.id, diff --git a/packages/backend/src/server/api/endpoints/admin/reject-quotes.ts b/packages/backend/src/server/api/endpoints/admin/reject-quotes.ts new file mode 100644 index 0000000000..78f94ceeff --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/reject-quotes.ts @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { UsersRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { CacheService } from '@/core/CacheService.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + kind: 'write:admin:reject-quotes', +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + rejectQuotes: { type: 'boolean', nullable: false }, + }, + required: ['userId', 'rejectQuotes'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.usersRepository) + private readonly usersRepository: UsersRepository, + + private readonly globalEventService: GlobalEventService, + private readonly cacheService: CacheService, + private readonly moderationLogService: ModerationLogService, + ) { + super(meta, paramDef, async (ps, me) => { + const user = await this.cacheService.findUserById(ps.userId); + + // Skip if there's nothing to do + if (user.rejectQuotes === ps.rejectQuotes) return; + + // Log event first. + // This ensures that we don't "lose" the log if an error occurs + await this.moderationLogService.log(me, ps.rejectQuotes ? 'rejectQuotesUser' : 'acceptQuotesUser', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + }); + + await this.usersRepository.update(ps.userId, { + rejectQuotes: ps.rejectQuotes, + }); + + // Synchronize caches and other processes + this.globalEventService.publishInternalEvent('localUserUpdated', { id: ps.userId }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index d1cf0123dc..b0f32bfda8 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -143,6 +143,12 @@ export const meta = { code: 'CONTAINS_TOO_MANY_MENTIONS', id: '4de0363a-3046-481b-9b0f-feff3e211025', }, + + quoteDisabledForUser: { + message: 'You do not have permission to create quote posts.', + code: 'QUOTE_DISABLED_FOR_USER', + id: '1c0ea108-d1e3-4e8e-aa3f-4d2487626153', + }, }, } as const; @@ -415,6 +421,8 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.containsProhibitedWords); } else if (e.id === '9f466dab-c856-48cd-9e65-ff90ff750580') { throw new ApiError(meta.errors.containsTooManyMentions); + } else if (e.id === '1c0ea108-d1e3-4e8e-aa3f-4d2487626153') { + throw new ApiError(meta.errors.quoteDisabledForUser); } } throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/edit.ts b/packages/backend/src/server/api/endpoints/notes/edit.ts index dc94c78e75..cc2293c5d6 100644 --- a/packages/backend/src/server/api/endpoints/notes/edit.ts +++ b/packages/backend/src/server/api/endpoints/notes/edit.ts @@ -176,6 +176,12 @@ export const meta = { id: '33510210-8452-094c-6227-4a6c05d99f02', }, + quoteDisabledForUser: { + message: 'You do not have permission to create quote posts.', + code: 'QUOTE_DISABLED_FOR_USER', + id: '1c0ea108-d1e3-4e8e-aa3f-4d2487626153', + }, + containsProhibitedWords: { message: 'Cannot post because it contains prohibited words.', code: 'CONTAINS_PROHIBITED_WORDS', @@ -469,6 +475,8 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.containsProhibitedWords); } else if (e.id === '9f466dab-c856-48cd-9e65-ff90ff750580') { throw new ApiError(meta.errors.containsTooManyMentions); + } else if (e.id === '1c0ea108-d1e3-4e8e-aa3f-4d2487626153') { + throw new ApiError(meta.errors.quoteDisabledForUser); } } throw e; diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index b359fa5a39..b5d982e3a5 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -132,6 +132,10 @@ export const moderationLogTypes = [ 'deletePage', 'deleteFlash', 'deleteGalleryPost', + 'acceptQuotesUser', + 'rejectQuotesUser', + 'acceptQuotesInstance', + 'rejectQuotesInstance', ] as const; export type ModerationLogPayloads = { @@ -417,6 +421,24 @@ export type ModerationLogPayloads = { postUserUsername: string; post: any; }; + acceptQuotesUser: { + userId: string, + userUsername: string, + userHost: string | null, + }; + rejectQuotesUser: { + userId: string, + userUsername: string, + userHost: string | null, + }; + acceptQuotesInstance: { + id: string; + host: string; + }; + rejectQuotesInstance: { + id: string; + host: string; + }; }; export type Serialized = { diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 0bac6a67b9..4b174d7336 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -142,7 +142,7 @@ SPDX-License-Identifier: AGPL-3.0-only