From b43de4ecfa1c3a3f95eadf5a481f666e838f1d9b Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 24 Sep 2025 20:16:20 +0900
Subject: [PATCH] wip
---
locales/ja-JP.yml | 1 +
packages/backend/src/models/Notification.ts | 6 +++
.../src/models/json-schema/notification.ts | 15 +++++++
.../backend/src/models/json-schema/user.ts | 1 +
.../PostScheduledNoteProcessorService.ts | 18 +++++---
.../server/api/endpoints/admin/show-user.ts | 1 +
.../src/server/api/endpoints/i/update.ts | 1 +
packages/backend/src/types.ts | 2 +
.../src/components/MkNotification.vue | 10 ++++-
packages/misskey-js/etc/misskey-js.api.md | 2 +-
packages/misskey-js/src/autogen/types.ts | 43 +++++++++++++++++--
packages/misskey-js/src/consts.ts | 1 +
12 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 1767e3da52..d6c4c14c3a 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2735,6 +2735,7 @@ _notification:
yourFollowRequestAccepted: "フォローリクエストが承認されました"
pollEnded: "アンケートの結果が出ました"
scheduledNotePosted: "予約ノートが投稿されました"
+ scheduledNotePostFailed: "予約ノートの投稿に失敗しました"
newNote: "新しい投稿"
unreadAntennaNote: "アンテナ {name}"
roleAssigned: "ロールが付与されました"
diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts
index fffd7fb4c3..7fa17e20fa 100644
--- a/packages/backend/src/models/Notification.ts
+++ b/packages/backend/src/models/Notification.ts
@@ -9,6 +9,7 @@ import { MiNote } from './Note.js';
import { MiAccessToken } from './AccessToken.js';
import { MiRole } from './Role.js';
import { MiDriveFile } from './DriveFile.js';
+import { MiNoteDraft } from './NoteDraft.js';
// misskey-js の notificationTypes と同期すべし
export type MiNotification = {
@@ -65,6 +66,11 @@ export type MiNotification = {
id: string;
createdAt: string;
noteId: MiNote['id'];
+} | {
+ type: 'scheduledNotePostFailed';
+ id: string;
+ createdAt: string;
+ noteDraftId: MiNoteDraft['id'];
} | {
type: 'receiveFollowRequest';
id: string;
diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts
index 8abe385164..30e9c9327a 100644
--- a/packages/backend/src/models/json-schema/notification.ts
+++ b/packages/backend/src/models/json-schema/notification.ts
@@ -222,6 +222,21 @@ export const packedNotificationSchema = {
optional: false, nullable: false,
},
},
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['scheduledNotePostFailed'],
+ },
+ noteDraft: {
+ type: 'object',
+ ref: 'NoteDraft',
+ optional: false, nullable: false,
+ },
+ },
}, {
type: 'object',
properties: {
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index a35b336017..b5fd38a7d7 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -610,6 +610,7 @@ export const packedMeDetailedOnlySchema = {
reaction: { optional: true, ...notificationRecieveConfig },
pollEnded: { optional: true, ...notificationRecieveConfig },
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
+ scheduledNotePostFailed: { optional: true, ...notificationRecieveConfig },
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
roleAssigned: { optional: true, ...notificationRecieveConfig },
diff --git a/packages/backend/src/queue/processors/PostScheduledNoteProcessorService.ts b/packages/backend/src/queue/processors/PostScheduledNoteProcessorService.ts
index 4793385990..914fa46e57 100644
--- a/packages/backend/src/queue/processors/PostScheduledNoteProcessorService.ts
+++ b/packages/backend/src/queue/processors/PostScheduledNoteProcessorService.ts
@@ -36,12 +36,20 @@ export class PostScheduledNoteProcessorService {
return;
}
- const note = await this.noteCreateService.create(draft.user, draft);
+ try {
+ const note = await this.noteCreateService.create(draft.user, draft);
- this.noteDraftsRepository.remove(draft);
+ // await不要
+ this.noteDraftsRepository.remove(draft);
- this.notificationService.createNotification(draft.userId, 'scheduledNotePosted', {
- noteId: note.id,
- });
+ // await不要
+ this.notificationService.createNotification(draft.userId, 'scheduledNotePosted', {
+ noteId: note.id,
+ });
+ } catch (err) {
+ this.notificationService.createNotification(draft.userId, 'scheduledNotePostFailed', {
+ noteDraftId: draft.id,
+ });
+ }
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts
index 7264d10137..2fd7ab8ca2 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts
@@ -104,6 +104,7 @@ export const meta = {
reaction: { optional: true, ...notificationRecieveConfig },
pollEnded: { optional: true, ...notificationRecieveConfig },
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
+ scheduledNotePostFailed: { optional: true, ...notificationRecieveConfig },
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
roleAssigned: { optional: true, ...notificationRecieveConfig },
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 96619247e0..5c7958fc1c 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -210,6 +210,7 @@ export const paramDef = {
reaction: notificationRecieveConfig,
pollEnded: notificationRecieveConfig,
scheduledNotePosted: notificationRecieveConfig,
+ scheduledNotePostFailed: notificationRecieveConfig,
receiveFollowRequest: notificationRecieveConfig,
followRequestAccepted: notificationRecieveConfig,
roleAssigned: notificationRecieveConfig,
diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts
index c3ede7afb1..24654b0017 100644
--- a/packages/backend/src/types.ts
+++ b/packages/backend/src/types.ts
@@ -13,6 +13,7 @@
* reaction - 投稿にリアクションされた
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
* scheduledNotePosted - 予約したノートが投稿された
+ * scheduledNotePostFailed - 予約したノートの投稿に失敗した
* receiveFollowRequest - フォローリクエストされた
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
* roleAssigned - ロールが付与された
@@ -34,6 +35,7 @@ export const notificationTypes = [
'reaction',
'pollEnded',
'scheduledNotePosted',
+ 'scheduledNotePostFailed',
'receiveFollowRequest',
'followRequestAccepted',
'roleAssigned',
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index 21df79a98e..45a74e3f02 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
@@ -24,6 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
[$style.t_quote]: notification.type === 'quote',
[$style.t_pollEnded]: notification.type === 'pollEnded',
[$style.t_scheduledNotePosted]: notification.type === 'scheduledNotePosted',
+ [$style.t_scheduledNotePostFailed]: notification.type === 'scheduledNotePostFailed',
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
[$style.t_login]: notification.type === 'login',
@@ -41,6 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
@@ -63,6 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts._notification.pollEnded }}
{{ i18n.ts._notification.scheduledNotePosted }}
+ {{ i18n.ts._notification.scheduledNotePostFailed }}
{{ i18n.ts._notification.newNote }}:
{{ i18n.ts._notification.roleAssigned }}
{{ i18n.ts._notification.chatRoomInvitationReceived }}
@@ -351,6 +354,11 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification)
pointer-events: none;
}
+.t_scheduledNotePostFailed {
+ background: var(--eventOther);
+ pointer-events: none;
+}
+
.t_achievementEarned {
background: var(--eventAchievement);
pointer-events: none;
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index b117ff4747..c41385e03d 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -3226,7 +3226,7 @@ type Notification_2 = components['schemas']['Notification'];
type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
// @public (undocumented)
-export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollEnded", "scheduledNotePosted", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
+export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollEnded", "scheduledNotePosted", "scheduledNotePostFailed", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
// @public (undocumented)
export function nyaize(text: string): string;
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 27e52267df..a4eb9f1b06 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4168,6 +4168,15 @@ export type components = {
/** Format: misskey:id */
userListId: string;
};
+ scheduledNotePostFailed?: {
+ /** @enum {string} */
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
+ } | {
+ /** @enum {string} */
+ type: 'list';
+ /** Format: misskey:id */
+ userListId: string;
+ };
receiveFollowRequest?: {
/** @enum {string} */
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
@@ -4580,6 +4589,14 @@ export type components = {
/** @enum {string} */
type: 'scheduledNotePosted';
note: components['schemas']['Note'];
+ } | {
+ /** Format: id */
+ id: string;
+ /** Format: date-time */
+ createdAt: string;
+ /** @enum {string} */
+ type: 'scheduledNotePostFailed';
+ noteDraft: components['schemas']['NoteDraft'];
} | {
/** Format: id */
id: string;
@@ -11681,6 +11698,15 @@ export interface operations {
/** Format: misskey:id */
userListId: string;
};
+ scheduledNotePostFailed?: {
+ /** @enum {string} */
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
+ } | {
+ /** @enum {string} */
+ type: 'list';
+ /** Format: misskey:id */
+ userListId: string;
+ };
receiveFollowRequest?: {
/** @enum {string} */
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
@@ -25982,8 +26008,8 @@ export interface operations {
untilDate?: number;
/** @default true */
markAsRead?: boolean;
- 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' | 'scheduledNotePosted' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
+ includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
+ excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
};
};
};
@@ -26067,8 +26093,8 @@ export interface operations {
untilDate?: number;
/** @default true */
markAsRead?: boolean;
- 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' | 'scheduledNotePosted' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
+ includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
+ excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
};
};
};
@@ -27351,6 +27377,15 @@ export interface operations {
/** Format: misskey:id */
userListId: string;
};
+ scheduledNotePostFailed?: {
+ /** @enum {string} */
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
+ } | {
+ /** @enum {string} */
+ type: 'list';
+ /** Format: misskey:id */
+ userListId: string;
+ };
receiveFollowRequest?: {
/** @enum {string} */
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts
index b68522cd30..e9f2cb1c31 100644
--- a/packages/misskey-js/src/consts.ts
+++ b/packages/misskey-js/src/consts.ts
@@ -27,6 +27,7 @@ export const notificationTypes = [
'reaction',
'pollEnded',
'scheduledNotePosted',
+ 'scheduledNotePostFailed',
'receiveFollowRequest',
'followRequestAccepted',
'groupInvited',