feat: 노트 게시를 예약할 수 있음 (yojo-art/cherrypick#483, [Type4ny-Project/Type4ny@271c872c](271c872c97))
This commit is contained in:
parent
92ffd2a5fc
commit
2528508cff
41 changed files with 1455 additions and 6 deletions
|
|
@ -42,6 +42,7 @@ import { TickChartsProcessorService } from './processors/TickChartsProcessorServ
|
|||
import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js';
|
||||
import { ExportFavoritesProcessorService } from './processors/ExportFavoritesProcessorService.js';
|
||||
import { RelationshipProcessorService } from './processors/RelationshipProcessorService.js';
|
||||
import { ScheduleNotePostProcessorService } from './processors/ScheduleNotePostProcessorService.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
@ -85,6 +86,7 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor
|
|||
InboxProcessorService,
|
||||
AggregateRetentionProcessorService,
|
||||
QueueProcessorService,
|
||||
ScheduleNotePostProcessorService,
|
||||
],
|
||||
exports: [
|
||||
QueueProcessorService,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMu
|
|||
import { BakeBufferedReactionsProcessorService } from './processors/BakeBufferedReactionsProcessorService.js';
|
||||
import { CleanProcessorService } from './processors/CleanProcessorService.js';
|
||||
import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js';
|
||||
import { ScheduleNotePostProcessorService } from './processors/ScheduleNotePostProcessorService.js';
|
||||
import { QueueLoggerService } from './QueueLoggerService.js';
|
||||
import { QUEUE, baseQueueOptions } from './const.js';
|
||||
import { ImportNotesProcessorService } from './processors/ImportNotesProcessorService.js';
|
||||
|
|
@ -86,6 +87,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
private relationshipQueueWorker: Bull.Worker;
|
||||
private objectStorageQueueWorker: Bull.Worker;
|
||||
private endedPollNotificationQueueWorker: Bull.Worker;
|
||||
private schedulerNotePostQueueWorker: Bull.Worker;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
|
|
@ -126,6 +128,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
private checkExpiredMutingsProcessorService: CheckExpiredMutingsProcessorService,
|
||||
private bakeBufferedReactionsProcessorService: BakeBufferedReactionsProcessorService,
|
||||
private cleanProcessorService: CleanProcessorService,
|
||||
private scheduleNotePostProcessorService: ScheduleNotePostProcessorService,
|
||||
) {
|
||||
this.logger = this.queueLoggerService.logger;
|
||||
|
||||
|
|
@ -530,6 +533,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
});
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region schedule note post
|
||||
{
|
||||
this.schedulerNotePostQueueWorker = new Bull.Worker(QUEUE.SCHEDULE_NOTE_POST, (job) => this.scheduleNotePostProcessorService.process(job), {
|
||||
...baseQueueOptions(this.config, QUEUE.SCHEDULE_NOTE_POST),
|
||||
autorun: false,
|
||||
});
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -544,6 +556,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
this.relationshipQueueWorker.run(),
|
||||
this.objectStorageQueueWorker.run(),
|
||||
this.endedPollNotificationQueueWorker.run(),
|
||||
this.schedulerNotePostQueueWorker.run(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -559,6 +572,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
this.relationshipQueueWorker.close(),
|
||||
this.objectStorageQueueWorker.close(),
|
||||
this.endedPollNotificationQueueWorker.close(),
|
||||
this.schedulerNotePostQueueWorker.close(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export const QUEUE = {
|
|||
OBJECT_STORAGE: 'objectStorage',
|
||||
USER_WEBHOOK_DELIVER: 'userWebhookDeliver',
|
||||
SYSTEM_WEBHOOK_DELIVER: 'systemWebhookDeliver',
|
||||
SCHEDULE_NOTE_POST: 'scheduleNotePost',
|
||||
};
|
||||
|
||||
export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type Logger from '@/logger.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||
import type { ChannelsRepository, DriveFilesRepository, MiDriveFile, NoteScheduleRepository, NotesRepository, UsersRepository } from '@/models/_.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||
import type * as Bull from 'bullmq';
|
||||
import type { ScheduleNotePostJobData } from '../types.js';
|
||||
|
||||
@Injectable()
|
||||
export class ScheduleNotePostProcessorService {
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.noteScheduleRepository)
|
||||
private noteScheduleRepository: NoteScheduleRepository,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
@Inject(DI.notesRepository)
|
||||
private notesRepository: NotesRepository,
|
||||
@Inject(DI.channelsRepository)
|
||||
private channelsRepository: ChannelsRepository,
|
||||
|
||||
private noteCreateService: NoteCreateService,
|
||||
private queueLoggerService: QueueLoggerService,
|
||||
) {
|
||||
this.logger = this.queueLoggerService.logger.createSubLogger('schedule-note-post');
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async process(job: Bull.Job<ScheduleNotePostJobData>): Promise<void> {
|
||||
this.noteScheduleRepository.findOneBy({ id: job.data.scheduleNoteId }).then(async (data) => {
|
||||
if (!data) {
|
||||
this.logger.warn(`Schedule note ${job.data.scheduleNoteId} not found`);
|
||||
} else {
|
||||
const me = await this.usersRepository.findOneBy({ id: data.userId });
|
||||
const note = data.note;
|
||||
|
||||
//idの形式でキューに積んであったのをDBから取り寄せる
|
||||
const reply = note.reply ? await this.notesRepository.findOneBy({ id: note.reply }) : undefined;
|
||||
const renote = note.reply ? await this.notesRepository.findOneBy({ id: note.renote }) : undefined;
|
||||
const channel = note.channel ? await this.channelsRepository.findOneBy({ id: note.channel, isArchived: false }) : undefined;
|
||||
let files: MiDriveFile[] = [];
|
||||
const fileIds = note.files ?? null;
|
||||
if (fileIds != null && fileIds.length > 0 && me) {
|
||||
files = await this.driveFilesRepository.createQueryBuilder('file')
|
||||
.where('file.userId = :userId AND file.id IN (:...fileIds)', {
|
||||
userId: me.id,
|
||||
fileIds,
|
||||
})
|
||||
.orderBy('array_position(ARRAY[:...fileIds], "id"::text)')
|
||||
.setParameters({ fileIds })
|
||||
.getMany();
|
||||
}
|
||||
if (
|
||||
!data.userId ||
|
||||
!me ||
|
||||
(note.reply && !reply) ||
|
||||
(note.renote && !renote) ||
|
||||
(note.channel && !channel) ||
|
||||
(note.files.length !== files.length)
|
||||
) {
|
||||
//キューに積んだときは有った物が消滅してたら予約投稿をキャンセルする
|
||||
this.logger.warn('cancel schedule note');
|
||||
await this.noteScheduleRepository.remove(data);
|
||||
return;
|
||||
}
|
||||
await this.noteCreateService.create(me, {
|
||||
...note,
|
||||
createdAt: new Date(note.createdAt), //typeORMのjsonbで何故かstringにされるから戻す
|
||||
files,
|
||||
poll: note.poll ? {
|
||||
choices: note.poll.choices,
|
||||
multiple: note.poll.multiple,
|
||||
expiresAt: note.poll.expiresAt ? new Date(note.poll.expiresAt) : null,
|
||||
} : undefined,
|
||||
reply,
|
||||
renote,
|
||||
channel,
|
||||
});
|
||||
await this.noteScheduleRepository.remove(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -155,3 +155,7 @@ export type UserWebhookDeliverJobData = {
|
|||
export type ThinUser = {
|
||||
id: MiUser['id'];
|
||||
};
|
||||
|
||||
export type ScheduleNotePostJobData = {
|
||||
scheduleNoteId: MiNote['id'];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue