summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/NoteEditService.ts
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-04-01 10:29:58 -0400
committerHazelnoot <acomputerdog@gmail.com>2025-04-01 10:29:58 -0400
commitea0371de34566ef6aee3682e9fe480fc0d347148 (patch)
tree6b4399b8b1bc8dcbb209ade0dd73f43f2c26808b /packages/backend/src/core/NoteEditService.ts
parentcopy changes to ApNoteService.updateNote (diff)
downloadsharkey-ea0371de34566ef6aee3682e9fe480fc0d347148.tar.gz
sharkey-ea0371de34566ef6aee3682e9fe480fc0d347148.tar.bz2
sharkey-ea0371de34566ef6aee3682e9fe480fc0d347148.zip
copy changes to NoteEditService.ts
Diffstat (limited to 'packages/backend/src/core/NoteEditService.ts')
-rw-r--r--packages/backend/src/core/NoteEditService.ts108
1 files changed, 17 insertions, 91 deletions
diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts
index ce6e6a9f03..7722beefc9 100644
--- a/packages/backend/src/core/NoteEditService.ts
+++ b/packages/backend/src/core/NoteEditService.ts
@@ -8,6 +8,7 @@ import * as mfm from '@transfem-org/sfm-js';
import { DataSource, In, IsNull, LessThan } from 'typeorm';
import * as Redis from 'ioredis';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
+import { UnrecoverableError } from 'bullmq';
import { extractMentions } from '@/misc/extract-mentions.js';
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
import { extractHashtags } from '@/misc/extract-hashtags.js';
@@ -36,7 +37,6 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
-import { NoteReadService } from '@/core/NoteReadService.js';
import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
@@ -203,7 +203,6 @@ export class NoteEditService implements OnApplicationShutdown {
private globalEventService: GlobalEventService,
private queueService: QueueService,
private fanoutTimelineService: FanoutTimelineService,
- private noteReadService: NoteReadService,
private notificationService: NotificationService,
private relayService: RelayService,
private federatedInstanceService: FederatedInstanceService,
@@ -233,7 +232,7 @@ export class NoteEditService implements OnApplicationShutdown {
noindex: MiUser['noindex'];
}, editid: MiNote['id'], data: Option, silent = false): Promise<MiNote> {
if (!editid) {
- throw new Error('fail');
+ throw new UnrecoverableError('edit failed: missing editid');
}
const oldnote = await this.notesRepository.findOneBy({
@@ -241,11 +240,11 @@ export class NoteEditService implements OnApplicationShutdown {
});
if (oldnote == null) {
- throw new Error('no such note');
+ throw new UnrecoverableError('edit failed: missing oldnote');
}
if (oldnote.userId !== user.id) {
- throw new Error('not the author');
+ throw new UnrecoverableError(`edit failed for ${oldnote.id}: user is not the note author`);
}
// we never want to change the replyId, so fetch the original "parent"
@@ -276,12 +275,12 @@ export class NoteEditService implements OnApplicationShutdown {
data.channel = await this.channelsRepository.findOneBy({ id: data.reply.channelId });
}
+ if (data.updatedAt == null) data.updatedAt = new Date();
if (data.visibility == null) data.visibility = 'public';
if (data.localOnly == null) data.localOnly = false;
if (data.channel != null) data.visibility = 'public';
if (data.channel != null) data.visibleUsers = [];
if (data.channel != null) data.localOnly = true;
- if (data.updatedAt == null) data.updatedAt = new Date();
if (data.visibility === 'public' && data.channel == null) {
const sensitiveWords = this.meta.sensitiveWords;
@@ -310,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 UnrecoverableError(`edit failed for ${oldnote.id}: cannot renote itself`);
}
switch (data.renote.visibility) {
@@ -406,10 +405,10 @@ export class NoteEditService implements OnApplicationShutdown {
// Parse MFM if needed
if (!tags || !emojis || !mentionedUsers) {
- const tokens = data.text ? mfm.parse(data.text)! : [];
- const cwTokens = data.cw ? mfm.parse(data.cw)! : [];
+ const tokens = data.text ? mfm.parse(data.text) : [];
+ const cwTokens = data.cw ? mfm.parse(data.cw) : [];
const choiceTokens = data.poll && data.poll.choices
- ? concat(data.poll.choices.map(choice => mfm.parse(choice)!))
+ ? concat(data.poll.choices.map(choice => mfm.parse(choice)))
: [];
const combinedTokens = tokens.concat(cwTokens).concat(choiceTokens);
@@ -424,7 +423,7 @@ export class NoteEditService implements OnApplicationShutdown {
// if the host is media-silenced, custom emojis are not allowed
if (this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, user.host)) emojis = [];
- tags = tags.filter(tag => Array.from(tag ?? '').length <= 128).splice(0, 32);
+ tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
mentionedUsers.push(await this.usersRepository.findOneByOrFail({ id: data.reply!.userId }));
@@ -467,10 +466,8 @@ export class NoteEditService implements OnApplicationShutdown {
update.hasPoll = !!data.poll;
}
- // technically we should check if the two sets of files are
- // different, or if their descriptions have changed. In practice
- // this is good enough.
- const filesChanged = oldnote.fileIds?.length || data.files?.length;
+ // TODO deep-compare files
+ const filesChanged = oldnote.fileIds.length || data.files?.length;
const poll = await this.pollsRepository.findOneBy({ noteId: oldnote.id });
@@ -564,7 +561,7 @@ export class NoteEditService implements OnApplicationShutdown {
noteVisibility: note.visibility,
userId: user.id,
userHost: user.host,
- channelId: data.channel ? data.channel.id : null,
+ channelId: data.channel?.id ?? null,
});
if (!oldnote.hasPoll) {
@@ -628,44 +625,12 @@ export class NoteEditService implements OnApplicationShutdown {
if (!silent) {
if (this.userEntityService.isLocalUser(user)) this.activeUsersChart.write(user);
- // 未読通知を作成
- if (data.visibility === 'specified') {
- if (data.visibleUsers == null) throw new Error('invalid param');
-
- for (const u of data.visibleUsers) {
- // ローカルユーザーのみ
- if (!this.userEntityService.isLocalUser(u)) continue;
-
- this.noteReadService.insertNoteUnread(u.id, note, {
- isSpecified: true,
- isMentioned: false,
- });
- }
- } else {
- for (const u of mentionedUsers) {
- // ローカルユーザーのみ
- if (!this.userEntityService.isLocalUser(u)) continue;
-
- this.noteReadService.insertNoteUnread(u.id, note, {
- isSpecified: false,
- isMentioned: true,
- });
- }
- }
-
// Pack the note
const noteObj = await this.noteEntityService.pack(note, null, { skipHide: true, withReactionAndUserPairCache: true });
- if (data.poll != null) {
- this.globalEventService.publishNoteStream(note.id, 'updated', {
- cw: note.cw,
- text: note.text!,
- });
- } else {
- this.globalEventService.publishNoteStream(note.id, 'updated', {
- cw: note.cw,
- text: note.text!,
- });
- }
+ this.globalEventService.publishNoteStream(note.id, 'updated', {
+ cw: note.cw,
+ text: note.text ?? '',
+ });
this.roleService.addNoteToRoleTimeline(noteObj);
@@ -673,8 +638,6 @@ export class NoteEditService implements OnApplicationShutdown {
const nm = new NotificationManager(this.mutingsRepository, this.notificationService, user, note);
- //await this.createMentionedEvents(mentionedUsers, note, nm);
-
// If has in reply to note
if (data.reply) {
// 通知
@@ -697,7 +660,6 @@ export class NoteEditService implements OnApplicationShutdown {
if (!isThreadMuted && !muted) {
nm.push(data.reply.userId, 'edited');
this.globalEventService.publishMainStream(data.reply.userId, 'edited', noteObj);
-
this.webhookService.enqueueUserWebhook(data.reply.userId, 'reply', { note: noteObj });
}
}
@@ -803,42 +765,6 @@ export class NoteEditService implements OnApplicationShutdown {
(note.files != null && note.files.length > 0);
}
- // TODO why is this unused?
- @bindThis
- private async createMentionedEvents(mentionedUsers: MinimumUser[], note: MiNote, nm: NotificationManager) {
- // FIXME only users the note is visible to should receive a notification, same as when a note is created
- for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
- const isThreadMuted = await this.noteThreadMutingsRepository.exists({
- where: {
- userId: u.id,
- threadId: note.threadId ?? note.id,
- },
- });
-
- const [
- userIdsWhoMeMuting,
- ] = u.id ? await Promise.all([
- this.cacheService.userMutingsCache.fetch(u.id),
- ]) : [new Set<string>()];
-
- const muted = isUserRelated(note, userIdsWhoMeMuting);
-
- if (isThreadMuted || muted) {
- continue;
- }
-
- const detailPackedNote = await this.noteEntityService.pack(note, u, {
- detail: true,
- });
-
- this.globalEventService.publishMainStream(u.id, 'edited', detailPackedNote);
- this.webhookService.enqueueUserWebhook(u.id, 'edited', { note: detailPackedNote });
-
- // Create notification
- nm.push(u.id, 'edited');
- }
- }
-
@bindThis
private async renderNoteOrRenoteActivity(data: Option, note: MiNote, user: MiUser) {
if (data.localOnly) return null;