diff --git a/locales/index.d.ts b/locales/index.d.ts index 39feda5075..5b7df00f93 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -10218,6 +10218,10 @@ export interface Locale extends ILocale { * Declined */ "decline": string; + /** + * Set content warning for user + */ + "setMandatoryCW": string; /** * Set remote instance as NSFW */ diff --git a/packages/backend/src/server/api/endpoints/admin/cw-user.ts b/packages/backend/src/server/api/endpoints/admin/cw-user.ts index d48ca565a4..bdcfa6a0d9 100644 --- a/packages/backend/src/server/api/endpoints/admin/cw-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/cw-user.ts @@ -9,6 +9,7 @@ import type { UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { CacheService } from '@/core/CacheService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], @@ -34,18 +35,31 @@ export default class extends Endpoint { // eslint- private readonly usersRepository: UsersRepository, private readonly globalEventService: GlobalEventService, + private readonly cacheService: CacheService, + private readonly moderationLogService: ModerationLogService, ) { - super(meta, paramDef, async ps => { - const result = await this.usersRepository.update(ps.userId, { + super(meta, paramDef, async (ps, me) => { + const user = await this.cacheService.findUserById(ps.userId); + + // Skip if there's nothing to do + if (user.mandatoryCW === ps.cw) return; + + // Log event first. + // This ensures that we don't "lose" the log if an error occurs + await this.moderationLogService.log(me, 'setMandatoryCW', { + newCW: ps.cw, + oldCW: user.mandatoryCW, + userId: user.id, + userUsername: user.username, + userHost: user.host, + }); + + 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/types.ts b/packages/backend/src/types.ts index 067481d9da..b359fa5a39 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -100,6 +100,7 @@ export const moderationLogTypes = [ 'deleteGlobalAnnouncement', 'deleteUserAnnouncement', 'resetPassword', + 'setMandatoryCW', 'setRemoteInstanceNSFW', 'unsetRemoteInstanceNSFW', 'suspendRemoteInstance', @@ -261,6 +262,13 @@ export type ModerationLogPayloads = { userUsername: string; userHost: string | null; }; + setMandatoryCW: { + newCW: string | null; + oldCW: string | null; + userId: string; + userUsername: string; + userHost: string | null; + }; setRemoteInstanceNSFW: { id: string; host: string; diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue index 2e5c820054..741de875bc 100644 --- a/packages/frontend/src/pages/admin/modlog.ModLog.vue +++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue @@ -22,6 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only [$style.logYellow]: [ 'markSensitiveDriveFile', 'resetPassword', + 'setMandatoryCW', 'suspendRemoteInstance', 'setRemoteInstanceNSFW', 'unsetRemoteInstanceNSFW', @@ -55,6 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} + : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} {{ log.info.roleName }} : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} {{ log.info.roleName }} : {{ log.info.role.name }} @@ -123,6 +125,12 @@ SPDX-License-Identifier: AGPL-3.0-only + diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index ee8bfe322c..25921d14c8 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2609,6 +2609,9 @@ type ModerationLog = { } | { type: 'deleteUserAnnouncement'; info: ModerationLogPayloads['deleteUserAnnouncement']; +} | { + type: 'setMandatoryCW'; + info: ModerationLogPayloads['setMandatoryCW']; } | { type: 'setRemoteInstanceNSFW'; info: ModerationLogPayloads['setRemoteInstanceNSFW']; @@ -2708,7 +2711,7 @@ type ModerationLog = { }); // @public (undocumented) -export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "approve", "decline", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "setRemoteInstanceNSFW", "unsetRemoteInstanceNSFW", "suspendRemoteInstance", "unsuspendRemoteInstance", "rejectRemoteInstanceReports", "acceptRemoteInstanceReports", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost"]; +export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "approve", "decline", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "setMandatoryCW", "setRemoteInstanceNSFW", "unsetRemoteInstanceNSFW", "suspendRemoteInstance", "unsuspendRemoteInstance", "rejectRemoteInstanceReports", "acceptRemoteInstanceReports", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost"]; // @public (undocumented) type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index fcb19be303..96da0a8fad 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -147,6 +147,7 @@ export const moderationLogTypes = [ 'deleteGlobalAnnouncement', 'deleteUserAnnouncement', 'resetPassword', + 'setMandatoryCW', 'setRemoteInstanceNSFW', 'unsetRemoteInstanceNSFW', 'suspendRemoteInstance', @@ -335,6 +336,13 @@ export type ModerationLogPayloads = { userUsername: string; userHost: string | null; }; + setMandatoryCW: { + newCW: string | null; + oldCW: string | null; + userId: string; + userUsername: string; + userHost: string | null; + }; setRemoteInstanceNSFW: { id: string; host: string; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index b92c2537a1..3e88eae275 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -118,8 +118,8 @@ export type ModerationLog = { type: 'deleteUserAnnouncement'; info: ModerationLogPayloads['deleteUserAnnouncement']; } | { - type: 'resetPassword'; - info: ModerationLogPayloads['resetPassword']; + type: 'setMandatoryCW'; + info: ModerationLogPayloads['setMandatoryCW']; } | { type: 'setRemoteInstanceNSFW'; info: ModerationLogPayloads['setRemoteInstanceNSFW']; diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index a12d84e2f5..84dd527694 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -304,6 +304,7 @@ _abuseReport: _moderationLogTypes: approve: "Approved" decline: "Declined" + setMandatoryCW: "Set content warning for user" setRemoteInstanceNSFW: "Set remote instance as NSFW" unsetRemoteInstanceNSFW: "Set remote instance as NSFW" rejectRemoteInstanceReports: "Rejected reports from remote instance"