Merge 8b1f889d1d
into 0f8c068e84
This commit is contained in:
commit
e756de996a
|
@ -4,6 +4,7 @@
|
||||||
- pnpm 10.16.0 が必要です
|
- pnpm 10.16.0 が必要です
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
- Feat: 予約投稿ができるようになりました
|
||||||
- Enhance: 広告ごとにセンシティブフラグを設定できるようになりました
|
- Enhance: 広告ごとにセンシティブフラグを設定できるようになりました
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
|
|
|
@ -5553,6 +5553,10 @@ export interface Locale extends ILocale {
|
||||||
* ユーザー指定ノートを作成
|
* ユーザー指定ノートを作成
|
||||||
*/
|
*/
|
||||||
"createUserSpecifiedNote": string;
|
"createUserSpecifiedNote": string;
|
||||||
|
/**
|
||||||
|
* 投稿を予約
|
||||||
|
*/
|
||||||
|
"schedulePost": string;
|
||||||
"_compression": {
|
"_compression": {
|
||||||
"_quality": {
|
"_quality": {
|
||||||
/**
|
/**
|
||||||
|
@ -10328,6 +10332,10 @@ export interface Locale extends ILocale {
|
||||||
* アンケートの結果が出ました
|
* アンケートの結果が出ました
|
||||||
*/
|
*/
|
||||||
"pollEnded": string;
|
"pollEnded": string;
|
||||||
|
/**
|
||||||
|
* 予約ノートが投稿されました
|
||||||
|
*/
|
||||||
|
"scheduledNotePosted": string;
|
||||||
/**
|
/**
|
||||||
* 新しい投稿
|
* 新しい投稿
|
||||||
*/
|
*/
|
||||||
|
@ -12641,6 +12649,10 @@ export interface Locale extends ILocale {
|
||||||
* 下書き一覧
|
* 下書き一覧
|
||||||
*/
|
*/
|
||||||
"listDrafts": string;
|
"listDrafts": string;
|
||||||
|
/**
|
||||||
|
* 投稿予約
|
||||||
|
*/
|
||||||
|
"schedule": string;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* 二次元コード
|
* 二次元コード
|
||||||
|
|
|
@ -1383,6 +1383,7 @@ customCssIsDisabledBecauseSafeMode: "セーフモードが有効なため、カ
|
||||||
themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
|
themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
|
||||||
thankYouForTestingBeta: "ベータ版の検証にご協力いただきありがとうございます!"
|
thankYouForTestingBeta: "ベータ版の検証にご協力いただきありがとうございます!"
|
||||||
createUserSpecifiedNote: "ユーザー指定ノートを作成"
|
createUserSpecifiedNote: "ユーザー指定ノートを作成"
|
||||||
|
schedulePost: "投稿を予約"
|
||||||
|
|
||||||
_compression:
|
_compression:
|
||||||
_quality:
|
_quality:
|
||||||
|
@ -2728,6 +2729,7 @@ _notification:
|
||||||
youReceivedFollowRequest: "フォローリクエストが来ました"
|
youReceivedFollowRequest: "フォローリクエストが来ました"
|
||||||
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
||||||
pollEnded: "アンケートの結果が出ました"
|
pollEnded: "アンケートの結果が出ました"
|
||||||
|
scheduledNotePosted: "予約ノートが投稿されました"
|
||||||
newNote: "新しい投稿"
|
newNote: "新しい投稿"
|
||||||
unreadAntennaNote: "アンテナ {name}"
|
unreadAntennaNote: "アンテナ {name}"
|
||||||
roleAssigned: "ロールが付与されました"
|
roleAssigned: "ロールが付与されました"
|
||||||
|
@ -3385,6 +3387,7 @@ _drafts:
|
||||||
restoreFromDraft: "下書きから復元"
|
restoreFromDraft: "下書きから復元"
|
||||||
restore: "復元"
|
restore: "復元"
|
||||||
listDrafts: "下書き一覧"
|
listDrafts: "下書き一覧"
|
||||||
|
schedule: "投稿予約"
|
||||||
|
|
||||||
qr: "二次元コード"
|
qr: "二次元コード"
|
||||||
_qr:
|
_qr:
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ScheduledPost1758677617888 {
|
||||||
|
name = 'ScheduledPost1758677617888'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {QueryRunner} queryRunner
|
||||||
|
*/
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "note_draft" ADD "scheduledAt" TIMESTAMP WITH TIME ZONE`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {QueryRunner} queryRunner
|
||||||
|
*/
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "note_draft" DROP COLUMN "scheduledAt"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import { IPoll } from '@/models/Poll.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { isRenote, isQuote } from '@/misc/is-renote.js';
|
import { isRenote, isQuote } from '@/misc/is-renote.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
|
|
||||||
export type NoteDraftOptions = {
|
export type NoteDraftOptions = {
|
||||||
replyId?: MiNote['id'] | null;
|
replyId?: MiNote['id'] | null;
|
||||||
|
@ -30,6 +31,7 @@ export type NoteDraftOptions = {
|
||||||
hashtag?: string;
|
hashtag?: string;
|
||||||
channelId?: MiChannel['id'] | null;
|
channelId?: MiChannel['id'] | null;
|
||||||
poll?: (IPoll & { expiredAfter?: number | null }) | null;
|
poll?: (IPoll & { expiredAfter?: number | null }) | null;
|
||||||
|
scheduledAt?: Date | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -56,6 +58,7 @@ export class NoteDraftService {
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
|
private queueService: QueueService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +98,11 @@ export class NoteDraftService {
|
||||||
|
|
||||||
appliedDraft.id = this.idService.gen();
|
appliedDraft.id = this.idService.gen();
|
||||||
appliedDraft.userId = me.id;
|
appliedDraft.userId = me.id;
|
||||||
const draft = this.noteDraftsRepository.save(appliedDraft);
|
const draft = await this.noteDraftsRepository.insertOne(appliedDraft);
|
||||||
|
|
||||||
|
if (draft.scheduledAt) {
|
||||||
|
this.schedule(draft);
|
||||||
|
}
|
||||||
|
|
||||||
return draft;
|
return draft;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +130,18 @@ export class NoteDraftService {
|
||||||
|
|
||||||
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, draft, data);
|
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, draft, data);
|
||||||
|
|
||||||
return await this.noteDraftsRepository.save(appliedDraft);
|
await this.noteDraftsRepository.update(draftId, appliedDraft);
|
||||||
|
|
||||||
|
this.clearSchedule(draft).then(() => {
|
||||||
|
if (appliedDraft.scheduledAt) {
|
||||||
|
this.schedule(draft);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...draft,
|
||||||
|
...appliedDraft,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -138,6 +156,8 @@ export class NoteDraftService {
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.noteDraftsRepository.delete(draft.id);
|
await this.noteDraftsRepository.delete(draft.id);
|
||||||
|
|
||||||
|
this.clearSchedule(draft);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -307,8 +327,40 @@ export class NoteDraftService {
|
||||||
visibleUserIds: data.visibleUserIds ?? [],
|
visibleUserIds: data.visibleUserIds ?? [],
|
||||||
localOnly: data.localOnly,
|
localOnly: data.localOnly,
|
||||||
reactionAcceptance: data.reactionAcceptance,
|
reactionAcceptance: data.reactionAcceptance,
|
||||||
|
scheduledAt: data.scheduledAt ?? null,
|
||||||
} satisfies MiNoteDraft;
|
} satisfies MiNoteDraft;
|
||||||
|
|
||||||
return appliedDraft;
|
return appliedDraft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async schedule(draft: MiNoteDraft): Promise<void> {
|
||||||
|
if (draft.scheduledAt == null) return;
|
||||||
|
if (draft.scheduledAt.getTime() <= Date.now()) return;
|
||||||
|
|
||||||
|
const delay = draft.scheduledAt.getTime() - Date.now();
|
||||||
|
this.queueService.postScheduledNoteQueue.add(draft.id, {
|
||||||
|
noteDraftId: draft.id,
|
||||||
|
}, {
|
||||||
|
delay,
|
||||||
|
removeOnComplete: {
|
||||||
|
age: 3600 * 24 * 7, // keep up to 7 days
|
||||||
|
count: 30,
|
||||||
|
},
|
||||||
|
removeOnFail: {
|
||||||
|
age: 3600 * 24 * 7, // keep up to 7 days
|
||||||
|
count: 100,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async clearSchedule(draft: MiNoteDraft): Promise<void> {
|
||||||
|
const jobs = await this.queueService.postScheduledNoteQueue.getJobs(['delayed', 'waiting', 'active']);
|
||||||
|
for (const job of jobs) {
|
||||||
|
if (job.data.noteDraftId === draft.id) {
|
||||||
|
await job.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,13 @@ import {
|
||||||
RelationshipJobData,
|
RelationshipJobData,
|
||||||
UserWebhookDeliverJobData,
|
UserWebhookDeliverJobData,
|
||||||
SystemWebhookDeliverJobData,
|
SystemWebhookDeliverJobData,
|
||||||
|
PostScheduledNoteJobData,
|
||||||
} from '../queue/types.js';
|
} from '../queue/types.js';
|
||||||
import type { Provider } from '@nestjs/common';
|
import type { Provider } from '@nestjs/common';
|
||||||
|
|
||||||
export type SystemQueue = Bull.Queue<Record<string, unknown>>;
|
export type SystemQueue = Bull.Queue<Record<string, unknown>>;
|
||||||
export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>;
|
export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>;
|
||||||
|
export type PostScheduledNoteQueue = Bull.Queue<PostScheduledNoteJobData>;
|
||||||
export type DeliverQueue = Bull.Queue<DeliverJobData>;
|
export type DeliverQueue = Bull.Queue<DeliverJobData>;
|
||||||
export type InboxQueue = Bull.Queue<InboxJobData>;
|
export type InboxQueue = Bull.Queue<InboxJobData>;
|
||||||
export type DbQueue = Bull.Queue;
|
export type DbQueue = Bull.Queue;
|
||||||
|
@ -41,6 +43,12 @@ const $endedPollNotification: Provider = {
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const $postScheduledNote: Provider = {
|
||||||
|
provide: 'queue:postScheduledNote',
|
||||||
|
useFactory: (config: Config) => new Bull.Queue(QUEUE.POST_SCHEDULED_NOTE, baseQueueOptions(config, QUEUE.POST_SCHEDULED_NOTE)),
|
||||||
|
inject: [DI.config],
|
||||||
|
};
|
||||||
|
|
||||||
const $deliver: Provider = {
|
const $deliver: Provider = {
|
||||||
provide: 'queue:deliver',
|
provide: 'queue:deliver',
|
||||||
useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)),
|
useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)),
|
||||||
|
@ -89,6 +97,7 @@ const $systemWebhookDeliver: Provider = {
|
||||||
providers: [
|
providers: [
|
||||||
$system,
|
$system,
|
||||||
$endedPollNotification,
|
$endedPollNotification,
|
||||||
|
$postScheduledNote,
|
||||||
$deliver,
|
$deliver,
|
||||||
$inbox,
|
$inbox,
|
||||||
$db,
|
$db,
|
||||||
|
@ -100,6 +109,7 @@ const $systemWebhookDeliver: Provider = {
|
||||||
exports: [
|
exports: [
|
||||||
$system,
|
$system,
|
||||||
$endedPollNotification,
|
$endedPollNotification,
|
||||||
|
$postScheduledNote,
|
||||||
$deliver,
|
$deliver,
|
||||||
$inbox,
|
$inbox,
|
||||||
$db,
|
$db,
|
||||||
|
@ -113,6 +123,7 @@ export class QueueModule implements OnApplicationShutdown {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
|
@Inject('queue:postScheduledNote') public postScheduledNoteQueue: PostScheduledNoteQueue,
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
|
@ -129,6 +140,7 @@ export class QueueModule implements OnApplicationShutdown {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.systemQueue.close(),
|
this.systemQueue.close(),
|
||||||
this.endedPollNotificationQueue.close(),
|
this.endedPollNotificationQueue.close(),
|
||||||
|
this.postScheduledNoteQueue.close(),
|
||||||
this.deliverQueue.close(),
|
this.deliverQueue.close(),
|
||||||
this.inboxQueue.close(),
|
this.inboxQueue.close(),
|
||||||
this.dbQueue.close(),
|
this.dbQueue.close(),
|
||||||
|
|
|
@ -31,6 +31,7 @@ import type {
|
||||||
DbQueue,
|
DbQueue,
|
||||||
DeliverQueue,
|
DeliverQueue,
|
||||||
EndedPollNotificationQueue,
|
EndedPollNotificationQueue,
|
||||||
|
PostScheduledNoteQueue,
|
||||||
InboxQueue,
|
InboxQueue,
|
||||||
ObjectStorageQueue,
|
ObjectStorageQueue,
|
||||||
RelationshipQueue,
|
RelationshipQueue,
|
||||||
|
@ -44,6 +45,7 @@ import type * as Bull from 'bullmq';
|
||||||
export const QUEUE_TYPES = [
|
export const QUEUE_TYPES = [
|
||||||
'system',
|
'system',
|
||||||
'endedPollNotification',
|
'endedPollNotification',
|
||||||
|
'postScheduledNote',
|
||||||
'deliver',
|
'deliver',
|
||||||
'inbox',
|
'inbox',
|
||||||
'db',
|
'db',
|
||||||
|
@ -92,6 +94,7 @@ export class QueueService {
|
||||||
|
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
|
@Inject('queue:postScheduledNote') public postScheduledNoteQueue: PostScheduledNoteQueue,
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
|
@ -717,6 +720,7 @@ export class QueueService {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'system': return this.systemQueue;
|
case 'system': return this.systemQueue;
|
||||||
case 'endedPollNotification': return this.endedPollNotificationQueue;
|
case 'endedPollNotification': return this.endedPollNotificationQueue;
|
||||||
|
case 'postScheduledNote': return this.postScheduledNoteQueue;
|
||||||
case 'deliver': return this.deliverQueue;
|
case 'deliver': return this.deliverQueue;
|
||||||
case 'inbox': return this.inboxQueue;
|
case 'inbox': return this.inboxQueue;
|
||||||
case 'db': return this.dbQueue;
|
case 'db': return this.dbQueue;
|
||||||
|
|
|
@ -105,6 +105,7 @@ export class NoteDraftEntityService implements OnModuleInit {
|
||||||
const packed: Packed<'NoteDraft'> = await awaitAll({
|
const packed: Packed<'NoteDraft'> = await awaitAll({
|
||||||
id: noteDraft.id,
|
id: noteDraft.id,
|
||||||
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
|
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
|
||||||
|
scheduledAt: noteDraft.scheduledAt?.getTime() ?? null,
|
||||||
userId: noteDraft.userId,
|
userId: noteDraft.userId,
|
||||||
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
|
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
|
||||||
text: text,
|
text: text,
|
||||||
|
|
|
@ -21,7 +21,18 @@ import type { OnModuleInit } from '@nestjs/common';
|
||||||
import type { UserEntityService } from './UserEntityService.js';
|
import type { UserEntityService } from './UserEntityService.js';
|
||||||
import type { NoteEntityService } from './NoteEntityService.js';
|
import type { NoteEntityService } from './NoteEntityService.js';
|
||||||
|
|
||||||
const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded'] as (typeof groupedNotificationTypes[number])[]);
|
const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set([
|
||||||
|
'note',
|
||||||
|
'mention',
|
||||||
|
'reply',
|
||||||
|
'renote',
|
||||||
|
'renote:grouped',
|
||||||
|
'quote',
|
||||||
|
'reaction',
|
||||||
|
'reaction:grouped',
|
||||||
|
'pollEnded',
|
||||||
|
'scheduledNotePosted',
|
||||||
|
] as (typeof groupedNotificationTypes[number])[]);
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NotificationEntityService implements OnModuleInit {
|
export class NotificationEntityService implements OnModuleInit {
|
||||||
|
|
|
@ -126,7 +126,7 @@ export class MiNoteDraft {
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public channel: MiChannel | null;
|
public channel: MiChannel | null;
|
||||||
|
|
||||||
// 以下、Pollについて追加
|
//#region 以下、Pollについて追加
|
||||||
|
|
||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -151,7 +151,13 @@ export class MiNoteDraft {
|
||||||
})
|
})
|
||||||
public pollExpiredAfter: number | null;
|
public pollExpiredAfter: number | null;
|
||||||
|
|
||||||
// ここまで追加
|
//#endregion
|
||||||
|
|
||||||
|
// 予約投稿
|
||||||
|
@Column('timestamp with time zone', {
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public scheduledAt: Date | null;
|
||||||
|
|
||||||
constructor(data: Partial<MiNoteDraft>) {
|
constructor(data: Partial<MiNoteDraft>) {
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
|
@ -60,6 +60,11 @@ export type MiNotification = {
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
notifierId: MiUser['id'];
|
notifierId: MiUser['id'];
|
||||||
noteId: MiNote['id'];
|
noteId: MiNote['id'];
|
||||||
|
} | {
|
||||||
|
type: 'scheduledNotePosted';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
noteId: MiNote['id'];
|
||||||
} | {
|
} | {
|
||||||
type: 'receiveFollowRequest';
|
type: 'receiveFollowRequest';
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -167,5 +167,9 @@ export const packedNoteDraftSchema = {
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
|
enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
|
||||||
},
|
},
|
||||||
|
scheduledAt: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -207,6 +207,21 @@ export const packedNotificationSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
...baseSchema.properties,
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
enum: ['scheduledNotePosted'],
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: 'object',
|
||||||
|
ref: 'Note',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
@ -609,6 +609,7 @@ export const packedMeDetailedOnlySchema = {
|
||||||
quote: { optional: true, ...notificationRecieveConfig },
|
quote: { optional: true, ...notificationRecieveConfig },
|
||||||
reaction: { optional: true, ...notificationRecieveConfig },
|
reaction: { optional: true, ...notificationRecieveConfig },
|
||||||
pollEnded: { optional: true, ...notificationRecieveConfig },
|
pollEnded: { optional: true, ...notificationRecieveConfig },
|
||||||
|
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
|
||||||
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
||||||
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
||||||
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { QueueLoggerService } from './QueueLoggerService.js';
|
||||||
import { QueueProcessorService } from './QueueProcessorService.js';
|
import { QueueProcessorService } from './QueueProcessorService.js';
|
||||||
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
||||||
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
||||||
|
import { PostScheduledNoteProcessorService } from './processors/PostScheduledNoteProcessorService.js';
|
||||||
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
||||||
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
||||||
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
||||||
|
@ -79,6 +80,7 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor
|
||||||
UserWebhookDeliverProcessorService,
|
UserWebhookDeliverProcessorService,
|
||||||
SystemWebhookDeliverProcessorService,
|
SystemWebhookDeliverProcessorService,
|
||||||
EndedPollNotificationProcessorService,
|
EndedPollNotificationProcessorService,
|
||||||
|
PostScheduledNoteProcessorService,
|
||||||
DeliverProcessorService,
|
DeliverProcessorService,
|
||||||
InboxProcessorService,
|
InboxProcessorService,
|
||||||
AggregateRetentionProcessorService,
|
AggregateRetentionProcessorService,
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { CheckModeratorsActivityProcessorService } from '@/queue/processors/Chec
|
||||||
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
||||||
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
||||||
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
||||||
|
import { PostScheduledNoteProcessorService } from './processors/PostScheduledNoteProcessorService.js';
|
||||||
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
||||||
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
||||||
import { DeleteDriveFilesProcessorService } from './processors/DeleteDriveFilesProcessorService.js';
|
import { DeleteDriveFilesProcessorService } from './processors/DeleteDriveFilesProcessorService.js';
|
||||||
|
@ -85,6 +86,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
private relationshipQueueWorker: Bull.Worker;
|
private relationshipQueueWorker: Bull.Worker;
|
||||||
private objectStorageQueueWorker: Bull.Worker;
|
private objectStorageQueueWorker: Bull.Worker;
|
||||||
private endedPollNotificationQueueWorker: Bull.Worker;
|
private endedPollNotificationQueueWorker: Bull.Worker;
|
||||||
|
private postScheduledNoteQueueWorker: Bull.Worker;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
|
@ -94,6 +96,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService,
|
private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService,
|
||||||
private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService,
|
private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService,
|
||||||
private endedPollNotificationProcessorService: EndedPollNotificationProcessorService,
|
private endedPollNotificationProcessorService: EndedPollNotificationProcessorService,
|
||||||
|
private postScheduledNoteProcessorService: PostScheduledNoteProcessorService,
|
||||||
private deliverProcessorService: DeliverProcessorService,
|
private deliverProcessorService: DeliverProcessorService,
|
||||||
private inboxProcessorService: InboxProcessorService,
|
private inboxProcessorService: InboxProcessorService,
|
||||||
private deleteDriveFilesProcessorService: DeleteDriveFilesProcessorService,
|
private deleteDriveFilesProcessorService: DeleteDriveFilesProcessorService,
|
||||||
|
@ -520,6 +523,21 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region post scheduled note
|
||||||
|
{
|
||||||
|
this.postScheduledNoteQueueWorker = new Bull.Worker(QUEUE.POST_SCHEDULED_NOTE, async (job) => {
|
||||||
|
if (this.config.sentryForBackend) {
|
||||||
|
return Sentry.startSpan({ name: 'Queue: PostScheduledNote' }, () => this.postScheduledNoteProcessorService.process(job));
|
||||||
|
} else {
|
||||||
|
return this.postScheduledNoteProcessorService.process(job);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
...baseWorkerOptions(this.config, QUEUE.POST_SCHEDULED_NOTE),
|
||||||
|
autorun: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -534,6 +552,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
this.relationshipQueueWorker.run(),
|
this.relationshipQueueWorker.run(),
|
||||||
this.objectStorageQueueWorker.run(),
|
this.objectStorageQueueWorker.run(),
|
||||||
this.endedPollNotificationQueueWorker.run(),
|
this.endedPollNotificationQueueWorker.run(),
|
||||||
|
this.postScheduledNoteQueueWorker.run(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,6 +568,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
this.relationshipQueueWorker.close(),
|
this.relationshipQueueWorker.close(),
|
||||||
this.objectStorageQueueWorker.close(),
|
this.objectStorageQueueWorker.close(),
|
||||||
this.endedPollNotificationQueueWorker.close(),
|
this.endedPollNotificationQueueWorker.close(),
|
||||||
|
this.postScheduledNoteQueueWorker.close(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const QUEUE = {
|
||||||
INBOX: 'inbox',
|
INBOX: 'inbox',
|
||||||
SYSTEM: 'system',
|
SYSTEM: 'system',
|
||||||
ENDED_POLL_NOTIFICATION: 'endedPollNotification',
|
ENDED_POLL_NOTIFICATION: 'endedPollNotification',
|
||||||
|
POST_SCHEDULED_NOTE: 'postScheduledNote',
|
||||||
DB: 'db',
|
DB: 'db',
|
||||||
RELATIONSHIP: 'relationship',
|
RELATIONSHIP: 'relationship',
|
||||||
OBJECT_STORAGE: 'objectStorage',
|
OBJECT_STORAGE: 'objectStorage',
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import type { NoteDraftsRepository } from '@/models/_.js';
|
||||||
|
import type Logger from '@/logger.js';
|
||||||
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||||
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
|
import type * as Bull from 'bullmq';
|
||||||
|
import type { PostScheduledNoteJobData } from '../types.js';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PostScheduledNoteProcessorService {
|
||||||
|
private logger: Logger;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.noteDraftsRepository)
|
||||||
|
private noteDraftsRepository: NoteDraftsRepository,
|
||||||
|
|
||||||
|
private noteCreateService: NoteCreateService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private queueLoggerService: QueueLoggerService,
|
||||||
|
) {
|
||||||
|
this.logger = this.queueLoggerService.logger.createSubLogger('post-scheduled-note');
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async process(job: Bull.Job<PostScheduledNoteJobData>): Promise<void> {
|
||||||
|
const draft = await this.noteDraftsRepository.findOne({ where: { id: job.data.noteDraftId }, relations: ['user'] });
|
||||||
|
if (draft == null || draft.user == null || draft.scheduledAt == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const note = await this.noteCreateService.create(draft.user, draft);
|
||||||
|
|
||||||
|
this.noteDraftsRepository.remove(draft);
|
||||||
|
|
||||||
|
this.notificationService.createNotification(draft.userId, 'scheduledNotePosted', {
|
||||||
|
noteId: note.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,6 +109,10 @@ export type EndedPollNotificationJobData = {
|
||||||
noteId: MiNote['id'];
|
noteId: MiNote['id'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PostScheduledNoteJobData = {
|
||||||
|
noteDraftId: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type SystemWebhookDeliverJobData<T extends SystemWebhookEventType = SystemWebhookEventType> = {
|
export type SystemWebhookDeliverJobData<T extends SystemWebhookEventType = SystemWebhookEventType> = {
|
||||||
type: T;
|
type: T;
|
||||||
content: SystemWebhookPayload<T>;
|
content: SystemWebhookPayload<T>;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, UserWebhookDeliverQueue, SystemWebhookDeliverQueue } from '@/core/QueueModule.js';
|
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, PostScheduledNoteQueue, InboxQueue, ObjectStorageQueue, SystemQueue, UserWebhookDeliverQueue, SystemWebhookDeliverQueue } from '@/core/QueueModule.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
@ -49,6 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
|
@Inject('queue:postScheduledNote') public postScheduledNoteQueue: PostScheduledNoteQueue,
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
|
|
|
@ -103,6 +103,7 @@ export const meta = {
|
||||||
quote: { optional: true, ...notificationRecieveConfig },
|
quote: { optional: true, ...notificationRecieveConfig },
|
||||||
reaction: { optional: true, ...notificationRecieveConfig },
|
reaction: { optional: true, ...notificationRecieveConfig },
|
||||||
pollEnded: { optional: true, ...notificationRecieveConfig },
|
pollEnded: { optional: true, ...notificationRecieveConfig },
|
||||||
|
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
|
||||||
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
||||||
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
||||||
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
||||||
|
|
|
@ -209,6 +209,7 @@ export const paramDef = {
|
||||||
quote: notificationRecieveConfig,
|
quote: notificationRecieveConfig,
|
||||||
reaction: notificationRecieveConfig,
|
reaction: notificationRecieveConfig,
|
||||||
pollEnded: notificationRecieveConfig,
|
pollEnded: notificationRecieveConfig,
|
||||||
|
scheduledNotePosted: notificationRecieveConfig,
|
||||||
receiveFollowRequest: notificationRecieveConfig,
|
receiveFollowRequest: notificationRecieveConfig,
|
||||||
followRequestAccepted: notificationRecieveConfig,
|
followRequestAccepted: notificationRecieveConfig,
|
||||||
roleAssigned: notificationRecieveConfig,
|
roleAssigned: notificationRecieveConfig,
|
||||||
|
|
|
@ -183,6 +183,7 @@ export const paramDef = {
|
||||||
},
|
},
|
||||||
required: ['choices'],
|
required: ['choices'],
|
||||||
},
|
},
|
||||||
|
scheduledAt: { type: 'integer', nullable: true },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -212,6 +213,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
visibility: ps.visibility,
|
visibility: ps.visibility,
|
||||||
visibleUserIds: ps.visibleUserIds ?? [],
|
visibleUserIds: ps.visibleUserIds ?? [],
|
||||||
channelId: ps.channelId ?? undefined,
|
channelId: ps.channelId ?? undefined,
|
||||||
|
scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
if (err instanceof IdentifiableError) {
|
if (err instanceof IdentifiableError) {
|
||||||
switch (err.id) {
|
switch (err.id) {
|
||||||
|
|
|
@ -215,6 +215,7 @@ export const paramDef = {
|
||||||
},
|
},
|
||||||
required: ['choices'],
|
required: ['choices'],
|
||||||
},
|
},
|
||||||
|
scheduledAt: { type: 'integer', nullable: true },
|
||||||
},
|
},
|
||||||
required: ['draftId'],
|
required: ['draftId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -244,6 +245,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
visibility: ps.visibility,
|
visibility: ps.visibility,
|
||||||
visibleUserIds: ps.visibleUserIds ?? [],
|
visibleUserIds: ps.visibleUserIds ?? [],
|
||||||
channelId: ps.channelId ?? undefined,
|
channelId: ps.channelId ?? undefined,
|
||||||
|
scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
if (err instanceof IdentifiableError) {
|
if (err instanceof IdentifiableError) {
|
||||||
switch (err.id) {
|
switch (err.id) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
* quote - 投稿が引用Renoteされた
|
* quote - 投稿が引用Renoteされた
|
||||||
* reaction - 投稿にリアクションされた
|
* reaction - 投稿にリアクションされた
|
||||||
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
||||||
|
* scheduledNotePosted - 予約したノートが投稿された
|
||||||
* receiveFollowRequest - フォローリクエストされた
|
* receiveFollowRequest - フォローリクエストされた
|
||||||
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
|
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
|
||||||
* roleAssigned - ロールが付与された
|
* roleAssigned - ロールが付与された
|
||||||
|
@ -32,6 +33,7 @@ export const notificationTypes = [
|
||||||
'quote',
|
'quote',
|
||||||
'reaction',
|
'reaction',
|
||||||
'pollEnded',
|
'pollEnded',
|
||||||
|
'scheduledNotePosted',
|
||||||
'receiveFollowRequest',
|
'receiveFollowRequest',
|
||||||
'followRequestAccepted',
|
'followRequestAccepted',
|
||||||
'roleAssigned',
|
'roleAssigned',
|
||||||
|
|
|
@ -94,12 +94,21 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i class="ti ti-corner-up-left"></i>
|
<i class="ti ti-corner-up-left"></i>
|
||||||
{{ i18n.ts._drafts.restore }}
|
{{ i18n.ts._drafts.restore }}
|
||||||
</MkButton>
|
</MkButton>
|
||||||
|
<MkButton
|
||||||
|
:class="$style.itemButton"
|
||||||
|
small
|
||||||
|
@click="schedule(draft)"
|
||||||
|
>
|
||||||
|
<i class="ti ti-calendar-time"></i>
|
||||||
|
{{ i18n.ts._drafts.schedule }}
|
||||||
|
</MkButton>
|
||||||
<MkButton
|
<MkButton
|
||||||
v-tooltip="i18n.ts._drafts.delete"
|
v-tooltip="i18n.ts._drafts.delete"
|
||||||
danger
|
danger
|
||||||
small
|
small
|
||||||
:iconOnly="true"
|
:iconOnly="true"
|
||||||
:class="$style.itemButton"
|
:class="$style.itemButton"
|
||||||
|
style="margin-left: auto;"
|
||||||
@click="deleteDraft(draft)"
|
@click="deleteDraft(draft)"
|
||||||
>
|
>
|
||||||
<i class="ti ti-trash"></i>
|
<i class="ti ti-trash"></i>
|
||||||
|
|
|
@ -23,6 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
[$style.t_mention]: notification.type === 'mention',
|
[$style.t_mention]: notification.type === 'mention',
|
||||||
[$style.t_quote]: notification.type === 'quote',
|
[$style.t_quote]: notification.type === 'quote',
|
||||||
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
||||||
|
[$style.t_scheduledNotePosted]: notification.type === 'scheduledNotePosted',
|
||||||
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
||||||
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
|
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
|
||||||
[$style.t_login]: notification.type === 'login',
|
[$style.t_login]: notification.type === 'login',
|
||||||
|
@ -39,6 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
|
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
|
||||||
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
|
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
|
||||||
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
||||||
|
<i v-else-if="notification.type === 'scheduledNotePosted'" class="ti ti-send"></i>
|
||||||
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
||||||
<i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i>
|
<i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i>
|
||||||
<i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i>
|
<i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i>
|
||||||
|
@ -60,6 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.tail">
|
<div :class="$style.tail">
|
||||||
<header :class="$style.header">
|
<header :class="$style.header">
|
||||||
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span>
|
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span>
|
||||||
|
<span v-else-if="notification.type === 'scheduledNotePosted'">{{ i18n.ts._notification.scheduledNotePosted }}</span>
|
||||||
<span v-else-if="notification.type === 'note'">{{ i18n.ts._notification.newNote }}: <MkUserName :user="notification.note.user"/></span>
|
<span v-else-if="notification.type === 'note'">{{ i18n.ts._notification.newNote }}: <MkUserName :user="notification.note.user"/></span>
|
||||||
<span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span>
|
<span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span>
|
||||||
<span v-else-if="notification.type === 'chatRoomInvitationReceived'">{{ i18n.ts._notification.chatRoomInvitationReceived }}</span>
|
<span v-else-if="notification.type === 'chatRoomInvitationReceived'">{{ i18n.ts._notification.chatRoomInvitationReceived }}</span>
|
||||||
|
@ -103,6 +106,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
||||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
</MkA>
|
</MkA>
|
||||||
|
<MkA v-else-if="notification.type === 'scheduledNotePosted'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
||||||
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
|
</MkA>
|
||||||
<div v-else-if="notification.type === 'roleAssigned'" :class="$style.text">
|
<div v-else-if="notification.type === 'roleAssigned'" :class="$style.text">
|
||||||
{{ notification.role.name }}
|
{{ notification.role.name }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -338,6 +346,11 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification)
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.t_scheduledNotePosted {
|
||||||
|
background: var(--eventOther);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.t_achievementEarned {
|
.t_achievementEarned {
|
||||||
background: var(--eventAchievement);
|
background: var(--eventAchievement);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
|
@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.headerLeft">
|
<div :class="$style.headerLeft">
|
||||||
<button v-if="!fixed" :class="$style.cancel" class="_button" @click="cancel"><i class="ti ti-x"></i></button>
|
<button v-if="!fixed" :class="$style.cancel" class="_button" @click="cancel"><i class="ti ti-x"></i></button>
|
||||||
<button v-click-anime v-tooltip="i18n.ts.switchAccount" :class="$style.account" class="_button" @click="openAccountMenu">
|
<button v-click-anime v-tooltip="i18n.ts.switchAccount" :class="$style.account" class="_button" @click="openAccountMenu">
|
||||||
<MkAvatar :user="postAccount ?? $i" :class="$style.avatar"/>
|
<img :class="$style.avatar" :src="(postAccount ?? $i).avatarUrl" style="border-radius: 100%;"/>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="$i.policies.noteDraftLimit > 0" v-tooltip="(postAccount != null && postAccount.id !== $i.id) ? null : i18n.ts.draft" class="_button" :class="$style.draftButton" :disabled="postAccount != null && postAccount.id !== $i.id" @click="showDraftMenu"><i class="ti ti-pencil-minus"></i></button>
|
<button v-if="$i.policies.noteDraftLimit > 0" v-tooltip="(postAccount != null && postAccount.id !== $i.id) ? null : i18n.ts.draft" class="_button" :class="$style.draftButton" :disabled="postAccount != null && postAccount.id !== $i.id" @click="showDraftMenu"><i class="ti ti-pencil-minus"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,6 +199,7 @@ if (props.initialVisibleUsers) {
|
||||||
props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
|
props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
|
||||||
}
|
}
|
||||||
const reactionAcceptance = ref(store.s.reactionAcceptance);
|
const reactionAcceptance = ref(store.s.reactionAcceptance);
|
||||||
|
const scheduledAt = ref<number | null>(null);
|
||||||
const draghover = ref(false);
|
const draghover = ref(false);
|
||||||
const quoteId = ref<string | null>(null);
|
const quoteId = ref<string | null>(null);
|
||||||
const hasNotSpecifiedMentions = ref(false);
|
const hasNotSpecifiedMentions = ref(false);
|
||||||
|
@ -414,6 +415,7 @@ function watchForDraft() {
|
||||||
watch(localOnly, () => saveDraft());
|
watch(localOnly, () => saveDraft());
|
||||||
watch(quoteId, () => saveDraft());
|
watch(quoteId, () => saveDraft());
|
||||||
watch(reactionAcceptance, () => saveDraft());
|
watch(reactionAcceptance, () => saveDraft());
|
||||||
|
watch(scheduledAt, () => saveDraft());
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkMissingMention() {
|
function checkMissingMention() {
|
||||||
|
@ -605,6 +607,12 @@ function showOtherSettings() {
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleReactionAcceptance();
|
toggleReactionAcceptance();
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
icon: 'ti ti-calendar-time',
|
||||||
|
text: i18n.ts.schedulePost + '...',
|
||||||
|
action: () => {
|
||||||
|
schedule();
|
||||||
|
},
|
||||||
}, { type: 'divider' }, {
|
}, { type: 'divider' }, {
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
icon: 'ti ti-eye',
|
icon: 'ti ti-eye',
|
||||||
|
@ -809,6 +817,7 @@ function saveDraft() {
|
||||||
...( visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
|
...( visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
|
||||||
quoteId: quoteId.value,
|
quoteId: quoteId.value,
|
||||||
reactionAcceptance: reactionAcceptance.value,
|
reactionAcceptance: reactionAcceptance.value,
|
||||||
|
scheduledAt: scheduledAt.value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -838,6 +847,7 @@ async function saveServerDraft(clearLocal = false) {
|
||||||
replyId: replyTargetNote.value ? replyTargetNote.value.id : undefined,
|
replyId: replyTargetNote.value ? replyTargetNote.value.id : undefined,
|
||||||
channelId: targetChannel.value ? targetChannel.value.id : undefined,
|
channelId: targetChannel.value ? targetChannel.value.id : undefined,
|
||||||
reactionAcceptance: reactionAcceptance.value,
|
reactionAcceptance: reactionAcceptance.value,
|
||||||
|
scheduledAt: scheduledAt.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (clearLocal) {
|
if (clearLocal) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -1175,6 +1185,7 @@ function showDraftMenu(ev: MouseEvent) {
|
||||||
renoteTargetNote.value = draft.renote;
|
renoteTargetNote.value = draft.renote;
|
||||||
replyTargetNote.value = draft.reply;
|
replyTargetNote.value = draft.reply;
|
||||||
reactionAcceptance.value = draft.reactionAcceptance;
|
reactionAcceptance.value = draft.reactionAcceptance;
|
||||||
|
scheduledAt.value = draft.scheduledAt ?? null;
|
||||||
if (draft.channel) targetChannel.value = draft.channel as unknown as Misskey.entities.Channel;
|
if (draft.channel) targetChannel.value = draft.channel as unknown as Misskey.entities.Channel;
|
||||||
|
|
||||||
visibleUsers.value = [];
|
visibleUsers.value = [];
|
||||||
|
@ -1220,6 +1231,13 @@ function showDraftMenu(ev: MouseEvent) {
|
||||||
}], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
|
}], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function schedule() {
|
||||||
|
const { canceled, result } = await os.inputDate({
|
||||||
|
title: i18n.ts.schedulePost,
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.autofocus) {
|
if (props.autofocus) {
|
||||||
focus();
|
focus();
|
||||||
|
@ -1255,6 +1273,7 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
quoteId.value = draft.data.quoteId;
|
quoteId.value = draft.data.quoteId;
|
||||||
reactionAcceptance.value = draft.data.reactionAcceptance;
|
reactionAcceptance.value = draft.data.reactionAcceptance;
|
||||||
|
scheduledAt.value = draft.data.scheduledAt ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3226,7 +3226,7 @@ type Notification_2 = components['schemas']['Notification'];
|
||||||
type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
|
type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
|
export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollEnded", "scheduledNotePosted", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function nyaize(text: string): string;
|
export function nyaize(text: string): string;
|
||||||
|
@ -3339,7 +3339,7 @@ type QueueStats = {
|
||||||
type QueueStatsLog = QueueStats[];
|
type QueueStatsLog = QueueStats[];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const queueTypes: readonly ["system", "endedPollNotification", "deliver", "inbox", "db", "relationship", "objectStorage", "userWebhookDeliver", "systemWebhookDeliver"];
|
export const queueTypes: readonly ["system", "endedPollNotification", "postScheduledNote", "deliver", "inbox", "db", "relationship", "objectStorage", "userWebhookDeliver", "systemWebhookDeliver"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RenoteMuteCreateRequest = operations['renote-mute___create']['requestBody']['content']['application/json'];
|
type RenoteMuteCreateRequest = operations['renote-mute___create']['requestBody']['content']['application/json'];
|
||||||
|
|
|
@ -4159,6 +4159,15 @@ export type components = {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
|
scheduledNotePosted?: {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
} | {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'list';
|
||||||
|
/** Format: misskey:id */
|
||||||
|
userListId: string;
|
||||||
|
};
|
||||||
receiveFollowRequest?: {
|
receiveFollowRequest?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
@ -4453,6 +4462,7 @@ export type components = {
|
||||||
localOnly?: boolean;
|
localOnly?: boolean;
|
||||||
/** @enum {string|null} */
|
/** @enum {string|null} */
|
||||||
reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
|
reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
|
||||||
|
scheduledAt: number | null;
|
||||||
};
|
};
|
||||||
NoteReaction: {
|
NoteReaction: {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
|
@ -4561,6 +4571,14 @@ export type components = {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
userId: string;
|
userId: string;
|
||||||
note: components['schemas']['Note'];
|
note: components['schemas']['Note'];
|
||||||
|
} | {
|
||||||
|
/** Format: id */
|
||||||
|
id: string;
|
||||||
|
/** Format: date-time */
|
||||||
|
createdAt: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'scheduledNotePosted';
|
||||||
|
note: components['schemas']['Note'];
|
||||||
} | {
|
} | {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -9553,7 +9571,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
state: '*' | 'completed' | 'wait' | 'active' | 'paused' | 'prioritized' | 'delayed' | 'failed';
|
state: '*' | 'completed' | 'wait' | 'active' | 'paused' | 'prioritized' | 'delayed' | 'failed';
|
||||||
};
|
};
|
||||||
|
@ -9740,7 +9758,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
state: ('active' | 'wait' | 'delayed' | 'completed' | 'failed' | 'paused')[];
|
state: ('active' | 'wait' | 'delayed' | 'completed' | 'failed' | 'paused')[];
|
||||||
search?: string;
|
search?: string;
|
||||||
};
|
};
|
||||||
|
@ -9808,7 +9826,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -9871,7 +9889,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -9884,7 +9902,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
name: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
name: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
qualifiedName: string;
|
qualifiedName: string;
|
||||||
counts: {
|
counts: {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
|
@ -9974,7 +9992,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
name: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
name: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
counts: {
|
counts: {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
};
|
};
|
||||||
|
@ -10038,7 +10056,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10102,7 +10120,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10166,7 +10184,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10233,7 +10251,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -11653,6 +11671,15 @@ export interface operations {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
|
scheduledNotePosted?: {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
} | {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'list';
|
||||||
|
/** Format: misskey:id */
|
||||||
|
userListId: string;
|
||||||
|
};
|
||||||
receiveFollowRequest?: {
|
receiveFollowRequest?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
@ -25954,8 +25981,8 @@ export interface operations {
|
||||||
untilDate?: number;
|
untilDate?: number;
|
||||||
/** @default true */
|
/** @default true */
|
||||||
markAsRead?: boolean;
|
markAsRead?: boolean;
|
||||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -26039,8 +26066,8 @@ export interface operations {
|
||||||
untilDate?: number;
|
untilDate?: number;
|
||||||
/** @default true */
|
/** @default true */
|
||||||
markAsRead?: boolean;
|
markAsRead?: boolean;
|
||||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -27314,6 +27341,15 @@ export interface operations {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
|
scheduledNotePosted?: {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
} | {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'list';
|
||||||
|
/** Format: misskey:id */
|
||||||
|
userListId: string;
|
||||||
|
};
|
||||||
receiveFollowRequest?: {
|
receiveFollowRequest?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
@ -29168,6 +29204,7 @@ export interface operations {
|
||||||
expiresAt?: number | null;
|
expiresAt?: number | null;
|
||||||
expiredAfter?: number | null;
|
expiredAfter?: number | null;
|
||||||
} | null;
|
} | null;
|
||||||
|
scheduledAt?: number | null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -29409,6 +29446,7 @@ export interface operations {
|
||||||
expiresAt?: number | null;
|
expiresAt?: number | null;
|
||||||
expiredAfter?: number | null;
|
expiredAfter?: number | null;
|
||||||
} | null;
|
} | null;
|
||||||
|
scheduledAt?: number | null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,6 +26,7 @@ export const notificationTypes = [
|
||||||
'quote',
|
'quote',
|
||||||
'reaction',
|
'reaction',
|
||||||
'pollEnded',
|
'pollEnded',
|
||||||
|
'scheduledNotePosted',
|
||||||
'receiveFollowRequest',
|
'receiveFollowRequest',
|
||||||
'followRequestAccepted',
|
'followRequestAccepted',
|
||||||
'groupInvited',
|
'groupInvited',
|
||||||
|
@ -233,6 +234,7 @@ export const rolePolicies = [
|
||||||
export const queueTypes = [
|
export const queueTypes = [
|
||||||
'system',
|
'system',
|
||||||
'endedPollNotification',
|
'endedPollNotification',
|
||||||
|
'postScheduledNote',
|
||||||
'deliver',
|
'deliver',
|
||||||
'inbox',
|
'inbox',
|
||||||
'db',
|
'db',
|
||||||
|
|
Loading…
Reference in New Issue