From a0e47980470b49e79e84ff3b7ccaf2b4502928c8 Mon Sep 17 00:00:00 2001 From: kozakura913 <98575220+kozakura913@users.noreply.github.com> Date: Sun, 3 Nov 2024 02:42:56 +0900 Subject: [PATCH] =?UTF-8?q?=E4=BA=88=E7=B4=84=E6=8A=95=E7=A8=BF=E3=81=AB?= =?UTF-8?q?=E5=A4=B1=E6=95=97=E3=81=97=E3=81=9F=E6=99=82=E3=81=AB=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E3=81=99=E3=82=8B=20(#523)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 26 +++++++++++++++++++ locales/ja-JP.yml | 7 +++++ .../entities/NotificationEntityService.ts | 3 +++ packages/backend/src/models/Notification.ts | 5 ++++ .../src/models/json-schema/notification.ts | 14 ++++++++++ .../ScheduleNotePostProcessorService.ts | 20 ++++++++++++++ packages/backend/src/types.ts | 1 + .../cherrypick-js/etc/cherrypick-js.api.md | 2 +- packages/cherrypick-js/src/autogen/types.ts | 16 +++++++++--- packages/cherrypick-js/src/consts.ts | 2 +- .../src/components/MkNotification.vue | 12 ++++++++- packages/frontend/src/const.ts | 1 + .../sw/src/scripts/create-notification.ts | 5 ++++ 13 files changed, 107 insertions(+), 7 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 128a90b568..cffcf088ac 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -10691,6 +10691,28 @@ export interface Locale extends ILocale { * 通知の履歴をリセットする */ "flushNotification": string; + "_scheduleNote": { + /** + * 原因は不明です + */ + "unknown": string; + /** + * 引用元がありません + */ + "renoteTargetNotFound": string; + /** + * 対象のチャンネルがありません + */ + "channelTargetNotFound": string; + /** + * 返信先がありません + */ + "replyTargetNotFound": string; + /** + * 添付ファイルがありません + */ + "invalidFilesCount": string; + }; "_types": { /** * すべて @@ -10748,6 +10770,10 @@ export interface Locale extends ILocale { * 実績の獲得 */ "achievementEarned": string; + /** + * 予約投稿に失敗 + */ + "scheduleNote": string; /** * 連携アプリからの通知 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b3a5a5d4a9..4bf6812f54 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2823,6 +2823,12 @@ _notification: notedBySomeUsers: "{n}件の新しい投稿" followedBySomeUsers: "{n}人にフォローされました" flushNotification: "通知の履歴をリセットする" + _scheduleNote: + unknown: "原因は不明です" + renoteTargetNotFound: "引用元がありません" + channelTargetNotFound: "対象のチャンネルがありません" + replyTargetNotFound: "返信先がありません" + invalidFilesCount: "添付ファイルがありません" _types: all: "すべて" @@ -2839,6 +2845,7 @@ _notification: groupInvited: "グループに招待された" roleAssigned: "ロールが付与された" achievementEarned: "実績の獲得" + scheduleNote: "予約投稿に失敗" app: "連携アプリからの通知" _actions: diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index f448a31bee..b785beef82 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -193,6 +193,9 @@ export class NotificationEntityService implements OnModuleInit { ...(notification.type === 'achievementEarned' ? { achievement: notification.achievement, } : {}), + ...(notification.type === 'scheduleNote' ? { + errorType: notification.errorType, + } : {}), ...(notification.type === 'app' ? { body: notification.customBody, header: notification.customHeader, diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index 0c966a4adb..d219100ddc 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -84,6 +84,11 @@ export type MiNotification = { id: string; createdAt: string; achievement: string; +} | { + type: 'scheduleNote'; + id: string; + createdAt: string; + errorType: string; } | { type: 'app'; id: string; diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index d941930916..4fc284f897 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -296,6 +296,20 @@ export const packedNotificationSchema = { optional: false, nullable: false, }, }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['scheduleNote'], + }, + errorType: { + type: 'string', + optional: false, nullable: false, + }, + }, }, { type: 'object', properties: { diff --git a/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts b/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts index 6b5b9db71b..550a340cd3 100644 --- a/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts +++ b/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts @@ -9,6 +9,7 @@ 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 { NotificationService } from '@/core/NotificationService.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type * as Bull from 'bullmq'; import type { ScheduleNotePostJobData } from '../types.js'; @@ -32,6 +33,7 @@ export class ScheduleNotePostProcessorService { private noteCreateService: NoteCreateService, private queueLoggerService: QueueLoggerService, + private notificationService: NotificationService, ) { this.logger = this.queueLoggerService.logger.createSubLogger('schedule-note-post'); } @@ -72,6 +74,24 @@ export class ScheduleNotePostProcessorService { //キューに積んだときは有った物が消滅してたら予約投稿をキャンセルする this.logger.warn('cancel schedule note'); await this.noteScheduleRepository.remove(data); + if (data.userId && me) {//ユーザーが特定できる場合に失敗を通知 + let errorType = 'unknown'; + if (note.renote && !renote) { + errorType = 'renoteTargetNotFound'; + } + if (note.reply && !reply) { + errorType = 'replyTargetNotFound'; + } + if (note.channel && !channel) { + errorType = 'channelTargetNotFound'; + } + if (note.files.length !== files.length) { + errorType = 'invalidFilesCount'; + } + this.notificationService.createNotification(data.userId, 'scheduleNote', { + errorType, + }); + } return; } await this.noteCreateService.create(me, { diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 7fbd139bee..5b18f3d769 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -34,6 +34,7 @@ export const notificationTypes = [ 'groupInvited', 'roleAssigned', 'achievementEarned', + 'scheduleNote', 'app', 'test', ] as const; diff --git a/packages/cherrypick-js/etc/cherrypick-js.api.md b/packages/cherrypick-js/etc/cherrypick-js.api.md index e1b18a298f..6a6b1544e9 100644 --- a/packages/cherrypick-js/etc/cherrypick-js.api.md +++ b/packages/cherrypick-js/etc/cherrypick-js.api.md @@ -2838,7 +2838,7 @@ type NotificationsCreateRequest = operations['notifications___create']['requestB type NotificationsDeleteRequest = operations['notifications___delete']['requestBody']['content']['application/json']; // @public (undocumented) -export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "achievementEarned"]; +export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "achievementEarned", "scheduleNote"]; // @public (undocumented) type OfficialTagsShowResponse = operations['official-tags___show']['responses']['200']['content']['application/json']; diff --git a/packages/cherrypick-js/src/autogen/types.ts b/packages/cherrypick-js/src/autogen/types.ts index de79188ae1..0e4cec9162 100644 --- a/packages/cherrypick-js/src/autogen/types.ts +++ b/packages/cherrypick-js/src/autogen/types.ts @@ -4598,6 +4598,14 @@ export type components = { /** @enum {string} */ type: 'achievementEarned'; achievement: string; + } | { + /** Format: id */ + id: string; + /** Format: date-time */ + createdAt: string; + /** @enum {string} */ + type: 'scheduleNote'; + errorType: string; } | { /** Format: id */ id: string; @@ -18786,8 +18794,8 @@ export type operations = { untilId?: string; /** @default true */ markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'scheduleNote' | 'app' | 'test' | 'pollVote')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'scheduleNote' | 'app' | 'test' | 'pollVote')[]; }; }; }; @@ -18854,8 +18862,8 @@ export type operations = { untilId?: string; /** @default true */ markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'note:grouped' | 'pollVote')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'note:grouped' | 'pollVote')[]; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'scheduleNote' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'note:grouped' | 'pollVote')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'roleAssigned' | 'achievementEarned' | 'scheduleNote' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'note:grouped' | 'pollVote')[]; }; }; }; diff --git a/packages/cherrypick-js/src/consts.ts b/packages/cherrypick-js/src/consts.ts index a6a113c8e3..303af81f12 100644 --- a/packages/cherrypick-js/src/consts.ts +++ b/packages/cherrypick-js/src/consts.ts @@ -16,7 +16,7 @@ import type { UserLite, } from './autogen/models.js'; -export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const; +export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned', 'scheduleNote'] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index c2c57e3978..92055cf891 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -12,6 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only