From 2943d3c3cd909af2acb2db3c56f57ee9b78df4f0 Mon Sep 17 00:00:00 2001 From: GrapeApple0 <84321396+GrapeApple0@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:25:59 +0000 Subject: [PATCH] =?UTF-8?q?=E5=85=B1=E9=80=9A=E3=81=AE=E9=96=A2=E6=95=B0?= =?UTF-8?q?=E3=82=92NoteEntityService=E3=81=AB=E7=B5=B1=E4=B8=80=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/src/core/NoteCreateService.ts | 33 +--------- packages/backend/src/core/NoteEditService.ts | 39 +---------- .../src/core/entities/NoteEntityService.ts | 66 ++++++++++++++++++- 3 files changed, 68 insertions(+), 70 deletions(-) diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 1d8d248322..e6fd3870f4 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -361,7 +361,7 @@ export class NoteCreateService implements OnApplicationShutdown { emojis = data.apEmojis ?? extractCustomEmojisFromMfm(combinedTokens); - mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens); + mentionedUsers = data.apMentions ?? await this.noteEntityService.ExtractMentionedUsers(user, combinedTokens); } // if the host is media-silenced, custom emojis are not allowed @@ -732,18 +732,6 @@ export class NoteCreateService implements OnApplicationShutdown { return note.renote != null; } - @bindThis - private isQuote(note: Option & { renote: MiNote }): note is Option & { renote: MiNote } & ( - { text: string } | { cw: string } | { reply: MiNote } | { poll: IPoll } | { files: MiDriveFile[] } - ) { - // NOTE: SYNC WITH misc/is-quote.ts - return note.text != null || - note.reply != null || - note.cw != null || - note.poll != null || - (note.files != null && note.files.length > 0); - } - @bindThis private incRenoteCount(renote: MiNote) { this.notesRepository.createQueryBuilder().update() @@ -809,7 +797,7 @@ export class NoteCreateService implements OnApplicationShutdown { private async renderNoteOrRenoteActivity(data: Option, note: MiNote) { if (data.localOnly) return null; - const content = this.isRenote(data) && !this.isQuote(data) + const content = this.isRenote(data) && !this.noteEntityService.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); @@ -834,23 +822,6 @@ export class NoteCreateService implements OnApplicationShutdown { .execute(); } - @bindThis - private async extractMentionedUsers(user: { host: MiUser['host']; }, tokens: mfm.MfmNode[]): Promise { - if (tokens == null) return []; - - const mentions = extractMentions(tokens); - let mentionedUsers = (await Promise.all(mentions.map(m => - this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null), - ))).filter(x => x != null); - - // Drop duplicate users - mentionedUsers = mentionedUsers.filter((u, i, self) => - i === self.findIndex(u2 => u.id === u2.id), - ); - - return mentionedUsers; - } - @bindThis private async pushToTl(note: MiNote, user: { id: MiUser['id']; host: MiUser['host']; }) { const meta = await this.metaService.fetch(); diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 9c0acb16a0..7221cf018c 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -7,7 +7,6 @@ import { setImmediate } from 'node:timers/promises'; import * as mfm from 'mfm-js'; import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { In, LessThan } from 'typeorm'; -import { extractMentions } from '@/misc/extract-mentions.js'; import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js'; import { extractHashtags } from '@/misc/extract-hashtags.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; @@ -47,13 +46,6 @@ import { UtilityService } from '@/core/UtilityService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; -type MinimumUser = { - id: MiUser['id']; - host: MiUser['host']; - username: MiUser['username']; - uri: MiUser['uri']; -}; - type Option = { publishedAt?: Date | null; name?: string | null; @@ -198,7 +190,7 @@ export class NoteEditService implements OnApplicationShutdown { } // Check blocking - if (data.renote && !this.isQuote(data)) { + if (data.renote && !this.noteEntityService.isQuote(data)) { if (data.renote.userHost === null) { if (data.renote.userId !== user.id) { const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id); @@ -236,7 +228,7 @@ export class NoteEditService implements OnApplicationShutdown { emojis = data.apEmojis ?? extractCustomEmojisFromMfm(combinedTokens); - mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens); + mentionedUsers = data.apMentions ?? await this.noteEntityService.ExtractMentionedUsers(user, combinedTokens); } tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32); @@ -437,17 +429,9 @@ export class NoteEditService implements OnApplicationShutdown { this.index(note); } - @bindThis - private isQuote(note: Option): note is Option & { renote: MiNote } { - // sync with misc/is-quote.ts - return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll); - } - @bindThis private async renderNoteOrRenoteActivity(data: Option, note: MiNote, userId: string) { - const content = data.renote && !this.isQuote(data) - ? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note) - : this.apRendererService.renderNoteUpdate(await this.apRendererService.renderNote(note, false, true), { id: userId }); + const content = this.apRendererService.renderNoteUpdate(await this.apRendererService.renderNote(note, false, true), { id: userId }); return this.apRendererService.addContext(content); } @@ -459,23 +443,6 @@ export class NoteEditService implements OnApplicationShutdown { this.searchService.indexNote(note); } - @bindThis - private async extractMentionedUsers(user: { host: MiUser['host']; }, tokens: mfm.MfmNode[]): Promise { - if (tokens == null) return []; - - const mentions = extractMentions(tokens); - let mentionedUsers = (await Promise.all(mentions.map(m => - this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null), - ))).filter(x => x != null) as MiUser[]; - - // Drop duplicate users - mentionedUsers = mentionedUsers.filter((u, i, self) => - i === self.findIndex(u2 => u.id === u2.id), - ); - - return mentionedUsers; - } - @bindThis public dispose(): void { this.#shutdownController.abort(); diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 17c846246e..863d92e1c3 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -4,24 +4,54 @@ */ import { Inject, Injectable } from '@nestjs/common'; +import * as mfm from 'mfm-js'; import { In } from 'typeorm'; import { ModuleRef } from '@nestjs/core'; import { DI } from '@/di-symbols.js'; import type { Packed } from '@/misc/json-schema.js'; import { awaitAll } from '@/misc/prelude/await-all.js'; -import type { MiUser } from '@/models/User.js'; -import type { MiNote } from '@/models/Note.js'; -import type { MiNoteReaction } from '@/models/NoteReaction.js'; +import { extractMentions } from '@/misc/extract-mentions.js'; +import type { MiUser, MiNote, MiDriveFile, MiApp, MiChannel, IPoll } from '@/models/_.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import { DebounceLoader } from '@/misc/loader.js'; import { IdService } from '@/core/IdService.js'; +import { RemoteUserResolveService } from '../RemoteUserResolveService.js'; import type { OnModuleInit } from '@nestjs/common'; import type { CustomEmojiService } from '../CustomEmojiService.js'; import type { ReactionService } from '../ReactionService.js'; import type { UserEntityService } from './UserEntityService.js'; import type { DriveFileEntityService } from './DriveFileEntityService.js'; +type MinimumUser = { + id: MiUser['id']; + host: MiUser['host']; + username: MiUser['username']; + uri: MiUser['uri']; +}; + +type Option = { + createdAt?: Date | null; + name?: string | null; + text?: string | null; + reply?: MiNote | null; + renote?: MiNote | null; + files?: MiDriveFile[] | null; + poll?: IPoll | null; + localOnly?: boolean | null; + reactionAcceptance?: MiNote['reactionAcceptance']; + cw?: string | null; + visibility?: string; + visibleUsers?: MinimumUser[] | null; + channel?: MiChannel | null; + apMentions?: MinimumUser[] | null; + apHashtags?: string[] | null; + apEmojis?: string[] | null; + uri?: string | null; + url?: string | null; + app?: MiApp | null; +}; + @Injectable() export class NoteEntityService implements OnModuleInit { private userEntityService: UserEntityService; @@ -59,6 +89,7 @@ export class NoteEntityService implements OnModuleInit { //private driveFileEntityService: DriveFileEntityService, //private customEmojiService: CustomEmojiService, //private reactionService: ReactionService, + private remoteUserResolveService: RemoteUserResolveService, ) { } @@ -500,4 +531,33 @@ export class NoteEntityService implements OnModuleInit { relations: ['user'], }); } + + @bindThis + public isQuote(note: Option): note is Option & ( + { text: string } | { cw: string } | { reply: MiNote } | { poll: IPoll } | { files: MiDriveFile[] } + ) { + // NOTE: SYNC WITH misc/is-quote.ts + return note.text != null || + note.reply != null || + note.cw != null || + note.poll != null || + (note.files != null && note.files.length > 0); + } + + @bindThis + public async ExtractMentionedUsers(user: { host: MiUser['host']; }, tokens: mfm.MfmNode[]): Promise { + if (tokens == null) return []; + + const mentions = extractMentions(tokens); + let mentionedUsers = (await Promise.all(mentions.map(m => + this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null), + ))).filter(x => x != null) as MiUser[]; + + // Drop duplicate users + mentionedUsers = mentionedUsers.filter((u, i, self) => + i === self.findIndex(u2 => u.id === u2.id), + ); + + return mentionedUsers; + } }