{
+ try {
+ return await promise;
+ } catch (err) {
+ if (err instanceof EntityNotFoundError) {
+ return null;
+ }
+ throw err;
+ }
+ }
+
const packed: Packed<'NoteDraft'> = await awaitAll({
id: noteDraft.id,
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
@@ -117,15 +129,15 @@ export class NoteDraftEntityService implements OnModuleInit {
} : undefined,
...(opts.detail ? {
- reply: noteDraft.replyId ? this.noteEntityService.pack(noteDraft.replyId, me, {
+ reply: noteDraft.replyId ? nullIfEntityNotFound(this.noteEntityService.pack(noteDraft.replyId, me, {
detail: false,
skipHide: opts.skipHide,
- }) : undefined,
+ })) : undefined,
- renote: noteDraft.renoteId ? this.noteEntityService.pack(noteDraft.renoteId, me, {
+ renote: noteDraft.renoteId ? nullIfEntityNotFound(this.noteEntityService.pack(noteDraft.renoteId, me, {
detail: true,
skipHide: opts.skipHide,
- }) : undefined,
+ })) : undefined,
poll: noteDraft.hasPoll ? {
choices: noteDraft.pollChoices,
diff --git a/packages/backend/src/models/NoteDraft.ts b/packages/backend/src/models/NoteDraft.ts
index edae254bb8..39d85e53dc 100644
--- a/packages/backend/src/models/NoteDraft.ts
+++ b/packages/backend/src/models/NoteDraft.ts
@@ -24,8 +24,9 @@ export class MiNoteDraft {
})
public replyId: MiNote['id'] | null;
+ // There is a possibility that replyId is not null but reply is null when the reply note is deleted.
@ManyToOne(type => MiNote, {
- onDelete: 'CASCADE',
+ createForeignKeyConstraints: false,
})
@JoinColumn()
public reply: MiNote | null;
@@ -38,8 +39,9 @@ export class MiNoteDraft {
})
public renoteId: MiNote['id'] | null;
+ // There is a possibility that renoteId is not null but renote is null when the renote note is deleted.
@ManyToOne(type => MiNote, {
- onDelete: 'CASCADE',
+ createForeignKeyConstraints: false,
})
@JoinColumn()
public renote: MiNote | null;
@@ -114,8 +116,10 @@ export class MiNoteDraft {
})
public channelId: MiChannel['id'] | null;
+ // There is a possibility that channelId is not null but channel is null when the channel is deleted.
+ // (deleting channel is not implemented so it's not happening now but may happen in the future)
@ManyToOne(type => MiChannel, {
- onDelete: 'CASCADE',
+ createForeignKeyConstraints: false,
})
@JoinColumn()
public channel: MiChannel | null;
diff --git a/packages/backend/src/models/json-schema/note-draft.ts b/packages/backend/src/models/json-schema/note-draft.ts
index 20c56d0795..504b263a6d 100644
--- a/packages/backend/src/models/json-schema/note-draft.ts
+++ b/packages/backend/src/models/json-schema/note-draft.ts
@@ -51,11 +51,13 @@ export const packedNoteDraftSchema = {
type: 'object',
optional: true, nullable: true,
ref: 'Note',
+ description: 'The reply target note contents if exists. If the reply target has been deleted since the draft was created, this will be null while replyId is not null.',
},
renote: {
type: 'object',
optional: true, nullable: true,
ref: 'Note',
+ description: 'The renote target note contents if exists. If the renote target has been deleted since the draft was created, this will be null while renoteId is not null.',
},
visibility: {
type: 'string',
diff --git a/packages/frontend/src/components/MkNoteDraftsDialog.vue b/packages/frontend/src/components/MkNoteDraftsDialog.vue
index 7d41740264..5b8211b715 100644
--- a/packages/frontend/src/components/MkNoteDraftsDialog.vue
+++ b/packages/frontend/src/components/MkNoteDraftsDialog.vue
@@ -42,6 +42,13 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+
+
+ {{ i18n.ts.deletedNote }}
+
+
+
@@ -50,6 +57,13 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+
+
+ {{ i18n.ts.deletedNote }}
+
+
+
{{ i18n.tsx._drafts.postTo({ channel: draft.channel.name }) }}
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 51e4b4f45d..7594117deb 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4401,7 +4401,9 @@ export type components = {
* @example xxxxxxxxxx
*/
renoteId?: string | null;
+ /** @description The reply target note contents if exists. If the reply target has been deleted since the draft was created, this will be null while replyId is not null. */
reply?: components['schemas']['Note'] | null;
+ /** @description The renote target note contents if exists. If the renote target has been deleted since the draft was created, this will be null while renoteId is not null. */
renote?: components['schemas']['Note'] | null;
/** @enum {string} */
visibility: 'public' | 'home' | 'followers' | 'specified';