共通の関数をNoteEntityServiceに統一化
This commit is contained in:
parent
a7b9e60c08
commit
2943d3c3cd
|
@ -361,7 +361,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
|
|
||||||
emojis = data.apEmojis ?? extractCustomEmojisFromMfm(combinedTokens);
|
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
|
// if the host is media-silenced, custom emojis are not allowed
|
||||||
|
@ -732,18 +732,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
return note.renote != null;
|
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
|
@bindThis
|
||||||
private incRenoteCount(renote: MiNote) {
|
private incRenoteCount(renote: MiNote) {
|
||||||
this.notesRepository.createQueryBuilder().update()
|
this.notesRepository.createQueryBuilder().update()
|
||||||
|
@ -809,7 +797,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
|
private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
|
||||||
if (data.localOnly) return null;
|
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.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, false), note);
|
||||||
|
|
||||||
|
@ -834,23 +822,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
|
||||||
private async extractMentionedUsers(user: { host: MiUser['host']; }, tokens: mfm.MfmNode[]): Promise<MiUser[]> {
|
|
||||||
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
|
@bindThis
|
||||||
private async pushToTl(note: MiNote, user: { id: MiUser['id']; host: MiUser['host']; }) {
|
private async pushToTl(note: MiNote, user: { id: MiUser['id']; host: MiUser['host']; }) {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { setImmediate } from 'node:timers/promises';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
||||||
import { In, LessThan } from 'typeorm';
|
import { In, LessThan } from 'typeorm';
|
||||||
import { extractMentions } from '@/misc/extract-mentions.js';
|
|
||||||
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
|
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
|
||||||
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
||||||
import type { IMentionedRemoteUsers } from '@/models/Note.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 { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
|
|
||||||
type MinimumUser = {
|
|
||||||
id: MiUser['id'];
|
|
||||||
host: MiUser['host'];
|
|
||||||
username: MiUser['username'];
|
|
||||||
uri: MiUser['uri'];
|
|
||||||
};
|
|
||||||
|
|
||||||
type Option = {
|
type Option = {
|
||||||
publishedAt?: Date | null;
|
publishedAt?: Date | null;
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
|
@ -198,7 +190,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check blocking
|
// Check blocking
|
||||||
if (data.renote && !this.isQuote(data)) {
|
if (data.renote && !this.noteEntityService.isQuote(data)) {
|
||||||
if (data.renote.userHost === null) {
|
if (data.renote.userHost === null) {
|
||||||
if (data.renote.userId !== user.id) {
|
if (data.renote.userId !== user.id) {
|
||||||
const blocked = await this.userBlockingService.checkBlocked(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);
|
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);
|
tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);
|
||||||
|
@ -437,17 +429,9 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
this.index(note);
|
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
|
@bindThis
|
||||||
private async renderNoteOrRenoteActivity(data: Option, note: MiNote, userId: string) {
|
private async renderNoteOrRenoteActivity(data: Option, note: MiNote, userId: string) {
|
||||||
const content = data.renote && !this.isQuote(data)
|
const content = this.apRendererService.renderNoteUpdate(await this.apRendererService.renderNote(note, false, true), { id: userId });
|
||||||
? 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 });
|
|
||||||
|
|
||||||
return this.apRendererService.addContext(content);
|
return this.apRendererService.addContext(content);
|
||||||
}
|
}
|
||||||
|
@ -459,23 +443,6 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
this.searchService.indexNote(note);
|
this.searchService.indexNote(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
|
||||||
private async extractMentionedUsers(user: { host: MiUser['host']; }, tokens: mfm.MfmNode[]): Promise<MiUser[]> {
|
|
||||||
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
|
@bindThis
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
this.#shutdownController.abort();
|
this.#shutdownController.abort();
|
||||||
|
|
|
@ -4,24 +4,54 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import * as mfm from 'mfm-js';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import { ModuleRef } from '@nestjs/core';
|
import { ModuleRef } from '@nestjs/core';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import { extractMentions } from '@/misc/extract-mentions.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiUser, MiNote, MiDriveFile, MiApp, MiChannel, IPoll } from '@/models/_.js';
|
||||||
import type { MiNoteReaction } from '@/models/NoteReaction.js';
|
|
||||||
import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository } from '@/models/_.js';
|
import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { DebounceLoader } from '@/misc/loader.js';
|
import { DebounceLoader } from '@/misc/loader.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { RemoteUserResolveService } from '../RemoteUserResolveService.js';
|
||||||
import type { OnModuleInit } from '@nestjs/common';
|
import type { OnModuleInit } from '@nestjs/common';
|
||||||
import type { CustomEmojiService } from '../CustomEmojiService.js';
|
import type { CustomEmojiService } from '../CustomEmojiService.js';
|
||||||
import type { ReactionService } from '../ReactionService.js';
|
import type { ReactionService } from '../ReactionService.js';
|
||||||
import type { UserEntityService } from './UserEntityService.js';
|
import type { UserEntityService } from './UserEntityService.js';
|
||||||
import type { DriveFileEntityService } from './DriveFileEntityService.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()
|
@Injectable()
|
||||||
export class NoteEntityService implements OnModuleInit {
|
export class NoteEntityService implements OnModuleInit {
|
||||||
private userEntityService: UserEntityService;
|
private userEntityService: UserEntityService;
|
||||||
|
@ -59,6 +89,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
//private driveFileEntityService: DriveFileEntityService,
|
//private driveFileEntityService: DriveFileEntityService,
|
||||||
//private customEmojiService: CustomEmojiService,
|
//private customEmojiService: CustomEmojiService,
|
||||||
//private reactionService: ReactionService,
|
//private reactionService: ReactionService,
|
||||||
|
private remoteUserResolveService: RemoteUserResolveService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,4 +531,33 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
relations: ['user'],
|
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<MiUser[]> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue