111 lines
3.6 KiB
TypeScript
111 lines
3.6 KiB
TypeScript
/*
|
|
* SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
import { Inject, Injectable } from '@nestjs/common';
|
|
import { And, In, MoreThan, Not } from 'typeorm';
|
|
import { DI } from '@/di-symbols.js';
|
|
import type { AutoRemovalConditionRepository, MiUserNotePining, NotesRepository, UserNotePiningsRepository, UsersRepository } from '@/models/_.js';
|
|
import type Logger from '@/logger.js';
|
|
import type { MiNote } from '@/models/Note.js';
|
|
import { bindThis } from '@/decorators.js';
|
|
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
|
|
import { IdService } from '@/core/IdService.js';
|
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
|
|
|
@Injectable()
|
|
export class AutoNoteRemovalProcessorService {
|
|
private logger: Logger;
|
|
|
|
constructor(
|
|
@Inject(DI.notesRepository)
|
|
private notesRepository: NotesRepository,
|
|
|
|
@Inject(DI.usersRepository)
|
|
private usersRepository: UsersRepository,
|
|
|
|
@Inject(DI.userNotePiningsRepository)
|
|
private userNotePiningsRepository: UserNotePiningsRepository,
|
|
|
|
@Inject(DI.autoRemovalConditionRepository)
|
|
private autoRemovalConditionRepository: AutoRemovalConditionRepository,
|
|
|
|
private idService: IdService,
|
|
private noteDeleteService: NoteDeleteService,
|
|
private queueLoggerService: QueueLoggerService,
|
|
) {
|
|
this.logger = this.queueLoggerService.logger.createSubLogger('auto-note-removal');
|
|
}
|
|
|
|
@bindThis
|
|
public async process(): Promise<void> {
|
|
this.logger.info('Checking notes that to remove automatically...');
|
|
this.logger.info('Checking users that enabled note auto-removal');
|
|
const users = await this.usersRepository.find({ where: { autoRemoval: true } });
|
|
if (users.length < 1) {
|
|
this.logger.info('Does not have any user that enabled autoRemoval');
|
|
return;
|
|
}
|
|
const now = Date.now();
|
|
|
|
for (const user of users) {
|
|
const autoRemovalCondition = await this.autoRemovalConditionRepository.findOneByOrFail({ id: user.autoRemovalConditionId });
|
|
const pinings: MiUserNotePining[] = await this.userNotePiningsRepository.findBy({ userId: user.id });
|
|
const piningNoteIds: string[] = pinings.map(pining => pining.noteId); // pining.note always undefined (bug?)
|
|
|
|
const specifiedNotes: MiNote[] = await this.notesRepository.findBy({
|
|
userId: user.id,
|
|
visibility: Not(In(['public', 'home', 'followers'])),
|
|
});
|
|
const specifiedNoteIds: string[] = specifiedNotes.map(note => note.id);
|
|
const deleteAfter: number = autoRemovalCondition.deleteAfter * 86400000;
|
|
|
|
// Delete notes
|
|
let cursor: MiNote['id'] | null = null;
|
|
let condition: string[] = [];
|
|
if (autoRemovalCondition.noSpecifiedNotes === true) {
|
|
condition = [...condition, ...specifiedNoteIds];
|
|
}
|
|
|
|
if (autoRemovalCondition.noPiningNotes === true) {
|
|
condition = [...condition, ...piningNoteIds];
|
|
}
|
|
|
|
while (true) {
|
|
const notes = await this.notesRepository.find({
|
|
where: {
|
|
userId: user.id,
|
|
...(cursor ? {
|
|
id: And(Not(In(condition)), MoreThan(cursor)),
|
|
} : {
|
|
id: Not(In(condition)),
|
|
}),
|
|
},
|
|
take: 100,
|
|
order: {
|
|
id: 1,
|
|
},
|
|
}) as MiNote[];
|
|
|
|
if (notes.length === 0) {
|
|
break;
|
|
}
|
|
|
|
cursor = notes.at(-1)?.id ?? null;
|
|
|
|
for (const note of notes) {
|
|
const createdAt: number = this.idService.parse(note.id).date.getTime();
|
|
const delta: number = now - createdAt;
|
|
if (delta > deleteAfter) {
|
|
await Promise.bind(this.noteDeleteService.delete(user, note, false, user));
|
|
}
|
|
}
|
|
}
|
|
|
|
this.logger.succ('All of auto-removable notes deleted');
|
|
}
|
|
|
|
this.logger.succ('All notes to auto-remove has beed removed.');
|
|
}
|
|
}
|