factor out latest_note logic into LatestNoteService
This commit is contained in:
parent
c55af9c3b3
commit
93cf2f9045
5 changed files with 167 additions and 115 deletions
|
|
@ -3,12 +3,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Brackets, In, Not } from 'typeorm';
|
||||
import { Brackets, In } from 'typeorm';
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||
import { MiNote, IMentionedRemoteUsers } from '@/models/Note.js';
|
||||
import { SkLatestNote } from '@/models/LatestNote.js';
|
||||
import type { InstancesRepository, LatestNotesRepository, NotesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/_.js';
|
||||
import { RelayService } from '@/core/RelayService.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
|
@ -20,12 +19,12 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
|
|||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { SearchService } from '@/core/SearchService.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { isPureRenote, isQuote, isRenote } from '@/misc/is-renote.js';
|
||||
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
||||
import { LatestNoteService } from '@/core/LatestNoteService.js';
|
||||
|
||||
@Injectable()
|
||||
export class NoteDeleteService {
|
||||
|
|
@ -39,14 +38,10 @@ export class NoteDeleteService {
|
|||
@Inject(DI.notesRepository)
|
||||
private notesRepository: NotesRepository,
|
||||
|
||||
@Inject(DI.latestNotesRepository)
|
||||
private latestNotesRepository: LatestNotesRepository,
|
||||
|
||||
@Inject(DI.instancesRepository)
|
||||
private instancesRepository: InstancesRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private relayService: RelayService,
|
||||
private federatedInstanceService: FederatedInstanceService,
|
||||
|
|
@ -58,6 +53,7 @@ export class NoteDeleteService {
|
|||
private notesChart: NotesChart,
|
||||
private perUserNotesChart: PerUserNotesChart,
|
||||
private instanceChart: InstanceChart,
|
||||
private latestNoteService: LatestNoteService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
@ -152,7 +148,7 @@ export class NoteDeleteService {
|
|||
userId: user.id,
|
||||
});
|
||||
|
||||
this.updateLatestNoteBG(note);
|
||||
this.latestNoteService.handleDeletedNoteBG(note);
|
||||
|
||||
if (deleter && (note.userId !== deleter.id)) {
|
||||
const user = await this.usersRepository.findOneByOrFail({ id: note.userId });
|
||||
|
|
@ -235,72 +231,4 @@ export class NoteDeleteService {
|
|||
this.apDeliverManagerService.deliverToUser(user, content, remoteUser);
|
||||
}
|
||||
}
|
||||
|
||||
private updateLatestNoteBG(note: MiNote): void {
|
||||
this
|
||||
.updateLatestNote(note)
|
||||
.catch(err => console.error('Unhandled exception while updating latest_note (after delete):', err));
|
||||
}
|
||||
|
||||
private async updateLatestNote(note: MiNote) {
|
||||
// If it's a DM, then it can't possibly be the latest note so we can safely skip this.
|
||||
if (note.visibility === 'specified') return;
|
||||
|
||||
// If it's a pure renote, then it can't possibly be the latest note so we can safely skip this.
|
||||
if (isPureRenote(note)) return;
|
||||
|
||||
// Compute the compound key of the entry to check
|
||||
const key = SkLatestNote.keyFor(note);
|
||||
|
||||
// Check if the deleted note was possibly the latest for the user
|
||||
const hasLatestNote = await this.latestNotesRepository.existsBy(key);
|
||||
if (hasLatestNote) return;
|
||||
|
||||
// Find the newest remaining note for the user.
|
||||
// We exclude DMs and pure renotes.
|
||||
const nextLatest = await this.notesRepository
|
||||
.createQueryBuilder('note')
|
||||
.select()
|
||||
.where({
|
||||
userId: key.userId,
|
||||
visibility: key.isPublic
|
||||
? 'public'
|
||||
: Not('specified'),
|
||||
replyId: key.isReply
|
||||
? Not(null)
|
||||
: null,
|
||||
renoteId: key.isQuote
|
||||
? Not(null)
|
||||
: null,
|
||||
})
|
||||
.andWhere(`
|
||||
(
|
||||
note."renoteId" IS NULL
|
||||
OR note.text IS NOT NULL
|
||||
OR note.cw IS NOT NULL
|
||||
OR note."replyId" IS NOT NULL
|
||||
OR note."hasPoll"
|
||||
OR note."fileIds" != '{}'
|
||||
)
|
||||
`)
|
||||
.orderBy({ id: 'DESC' })
|
||||
.getOne();
|
||||
if (!nextLatest) return;
|
||||
|
||||
// Record it as the latest
|
||||
const latestNote = new SkLatestNote({
|
||||
...key,
|
||||
noteId: nextLatest.id,
|
||||
});
|
||||
|
||||
// When inserting the latest note, it's possible that another worker has "raced" the insert and already added a newer note.
|
||||
// We must use orIgnore() to ensure that the query ignores conflicts, otherwise an exception may be thrown.
|
||||
await this.latestNotesRepository
|
||||
.createQueryBuilder('latest')
|
||||
.insert()
|
||||
.into(SkLatestNote)
|
||||
.values(latestNote)
|
||||
.orIgnore()
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue