fix cw-note erasing parts of the note

This commit is contained in:
Hazelnoot 2025-09-19 12:01:36 -04:00
parent e68e0266a4
commit 0e6caa625c
2 changed files with 55 additions and 9 deletions

View file

@ -118,7 +118,7 @@ type MinimumUser = {
uri: MiUser['uri'];
};
type Option = {
export type Option = {
createdAt?: Date | null;
name?: string | null;
text?: string | null;

View file

@ -4,11 +4,14 @@
*/
import { Inject, Injectable } from '@nestjs/common';
import { In } from 'typeorm';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { MiNote, MiUser, NotesRepository } from '@/models/_.js';
import type { ChannelsRepository, DriveFilesRepository, MiNote, NotesRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { NoteEditService } from '@/core/NoteEditService.js';
import { NoteEditService, Option } from '@/core/NoteEditService.js';
import { CacheService } from '@/core/CacheService.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
export const meta = {
tags: ['admin'],
@ -35,14 +38,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.notesRepository)
private readonly notesRepository: NotesRepository,
@Inject(DI.driveFilesRepository)
private readonly driveFilesRepository: DriveFilesRepository,
@Inject(DI.channelsRepository)
private readonly channelsRepository: ChannelsRepository,
private readonly noteEditService: NoteEditService,
private readonly moderationLogService: ModerationLogService,
private readonly cacheService: CacheService,
) {
super(meta, paramDef, async (ps, me) => {
const note = await this.notesRepository.findOneOrFail({
where: { id: ps.noteId },
relations: { user: true },
}) as MiNote & { user: MiUser };
relations: { reply: true, renote: true, channel: true },
});
const user = await this.cacheService.findUserById(note.userId);
// Collapse empty strings to null
const newCW = ps.cw?.trim() || null;
@ -51,16 +62,51 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// Skip if there's nothing to do
if (oldCW === newCW) return;
await this.noteEditService.edit(note.user, note.id, { mandatoryCW: newCW });
// TODO remove this after merging hazelnoot/fix-note-edit-logic.
// Until then, we have to ensure that everything is populated just like it would be from notes/edit.ts.
// Otherwise forcing a CW will erase everything else in the note.
// After merging remove all the "createUpdate" stuff and just pass "{ mandatoryCW: newCW }" into noteEditService.edit().
const update = await this.createUpdate(note, newCW);
await this.noteEditService.edit(user, note.id, update);
await this.moderationLogService.log(me, 'setMandatoryCWForNote', {
newCW,
oldCW,
noteId: note.id,
noteUserId: note.user.id,
noteUserUsername: note.user.username,
noteUserHost: note.user.host,
noteUserId: user.id,
noteUserUsername: user.username,
noteUserHost: user.host,
});
});
}
// Note: user must be fetched with reply, renote, and channel relations populated
private async createUpdate(note: MiNote, newCW: string | null) {
// This is based on the call to NoteEditService.edit from notes/edit endpoint.
// noinspection ES6MissingAwait
return await awaitAll<Option>({
// Preserve these from original note
files: note.fileIds.length > 0
? this.driveFilesRepository.findBy({ id: In(note.fileIds) }) : null,
poll: undefined,
text: undefined,
cw: undefined,
reply: note.reply
?? (note.replyId ? this.notesRepository.findOneByOrFail({ id: note.replyId }) : null),
renote: note.renote
?? (note.renoteId ? this.notesRepository.findOneByOrFail({ id: note.renoteId }) : null),
localOnly: note.localOnly,
reactionAcceptance: note.reactionAcceptance,
visibility: note.visibility,
visibleUsers: note.visibleUserIds.length > 0
? this.cacheService.getUsers(note.visibleUserIds).then(us => Array.from(us.values())) : null,
channel: note.channel ?? (note.channelId ? this.channelsRepository.findOneByOrFail({ id: note.channelId }) : null),
apMentions: undefined,
apHashtags: undefined,
apEmojis: undefined,
// But override the mandatory CW!
mandatoryCW: newCW,
});
}
}