diff options
| author | lqvp <183242690+lqvp@users.noreply.github.com> | 2025-02-11 10:15:33 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-11 01:15:33 +0000 |
| commit | e3392936736c16000b837f1549943d2f241e01b2 (patch) | |
| tree | 6b2c743e5982e990ce6ec832706f95642eccb6dd | |
| parent | fix(frontend): コンディショナルロールを手動で割り当てで... (diff) | |
| download | sharkey-e3392936736c16000b837f1549943d2f241e01b2.tar.gz sharkey-e3392936736c16000b837f1549943d2f241e01b2.tar.bz2 sharkey-e3392936736c16000b837f1549943d2f241e01b2.zip | |
feat: アクセストークン発行時に通知するように (#15422)
* feat: アクセストークン発行時に通知するように (misskey-dev/misskey#13353)
* fix: 不要な翻訳を削除/インデントを揃えるように
* chore(backend): 不要なawaitを削除
* chore: changelogへ追加
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | locales/index.d.ts | 8 | ||||
| -rw-r--r-- | locales/ja-JP.yml | 2 | ||||
| -rw-r--r-- | packages/backend/src/models/Notification.ts | 4 | ||||
| -rw-r--r-- | packages/backend/src/models/json-schema/notification.ts | 10 | ||||
| -rw-r--r-- | packages/backend/src/server/api/endpoints/miauth/gen-token.ts | 5 | ||||
| -rw-r--r-- | packages/backend/src/types.ts | 2 | ||||
| -rw-r--r-- | packages/frontend-shared/js/const.ts | 1 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkNotification.vue | 14 | ||||
| -rw-r--r-- | packages/frontend/src/pages/settings/notifications.vue | 2 | ||||
| -rw-r--r-- | packages/misskey-js/src/autogen/types.ts | 15 |
11 files changed, 58 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 39f948597d..bdef319c2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## Unreleased ### General -- +- Feat: アクセストークン発行時に通知するように ### Client - Enhance: 投稿フォームの「迷惑になる可能性があります」のダイアログを表示する条件においてCWを考慮するように diff --git a/locales/index.d.ts b/locales/index.d.ts index 4e4e95b6ed..4fe605490e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -9472,6 +9472,14 @@ export interface Locale extends ILocale { * ログインがありました */ "login": string; + /** + * アクセストークンが作成されました + */ + "createToken": string; + /** + * 心当たりがない場合は「{text}」を通じてアクセストークンを削除してください。 + */ + "createTokenDescription": ParameterizedString<"text">; "_types": { /** * すべて diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index ea18cc063c..57b11e9e04 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2500,6 +2500,8 @@ _notification: flushNotification: "通知の履歴をリセットする" exportOfXCompleted: "{x}のエクスポートが完了しました" login: "ログインがありました" + createToken: "アクセストークンが作成されました" + createTokenDescription: "心当たりがない場合は「{text}」を通じてアクセストークンを削除してください。" _types: all: "すべて" diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index b7f8e94d69..5772ace338 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -91,6 +91,10 @@ export type MiNotification = { id: string; createdAt: string; } | { + type: 'createToken'; + id: string; + createdAt: string; +} | { type: 'app'; id: string; createdAt: string; diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index cddaf4bc83..1638b2b3c7 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -339,6 +339,16 @@ export const packedNotificationSchema = { type: { type: 'string', optional: false, nullable: false, + enum: ['createToken'], + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, enum: ['app'], }, body: { diff --git a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts index fc9a8f3ebe..f1e3726641 100644 --- a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts +++ b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { AccessTokensRepository } from '@/models/_.js'; import { IdService } from '@/core/IdService.js'; +import { NotificationService } from '@/core/NotificationService.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; import { DI } from '@/di-symbols.js'; @@ -50,6 +51,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- private accessTokensRepository: AccessTokensRepository, private idService: IdService, + private notificationService: NotificationService, ) { super(meta, paramDef, async (ps, me) => { // Generate access token @@ -71,6 +73,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- permission: ps.permission, }); + // アクセストークンが生成されたことを通知 + this.notificationService.createNotification(me.id, 'createToken', {}); + return { token: accessToken, }; diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index df3cfee171..bf409031c8 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -18,6 +18,7 @@ * achievementEarned - 実績を獲得 * exportCompleted - エクスポートが完了 * login - ログイン + * createToken - トークン作成 * app - アプリ通知 * test - テスト通知(サーバー側) */ @@ -36,6 +37,7 @@ export const notificationTypes = [ 'achievementEarned', 'exportCompleted', 'login', + 'createToken', 'app', 'test', ] as const; diff --git a/packages/frontend-shared/js/const.ts b/packages/frontend-shared/js/const.ts index 4fe5cbb205..9e20479e26 100644 --- a/packages/frontend-shared/js/const.ts +++ b/packages/frontend-shared/js/const.ts @@ -69,6 +69,7 @@ export const notificationTypes = [ 'achievementEarned', 'exportCompleted', 'login', + 'createToken', 'test', 'app', ] as const; diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index 093bdb8b4c..80cb9a45bb 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 <div :class="$style.root"> <div :class="$style.head"> <MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/> - <MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/> + <MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login', 'createToken'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/> <div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div> <div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div> <div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div> @@ -27,6 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only [$style.t_achievementEarned]: notification.type === 'achievementEarned', [$style.t_exportCompleted]: notification.type === 'exportCompleted', [$style.t_login]: notification.type === 'login', + [$style.t_createToken]: notification.type === 'createToken', [$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null, }]" > @@ -41,6 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only <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 === 'login'" class="ti ti-login-2"></i> + <i v-else-if="notification.type === 'createToken'" class="ti ti-key"></i> <template v-else-if="notification.type === 'roleAssigned'"> <img v-if="notification.role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="notification.role.iconUrl" alt=""/> <i v-else class="ti ti-badges"></i> @@ -61,6 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only <span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span> <span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span> <span v-else-if="notification.type === 'login'">{{ i18n.ts._notification.login }}</span> + <span v-else-if="notification.type === 'createToken'">{{ i18n.ts._notification.createToken }}</span> <span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span> <span v-else-if="notification.type === 'exportCompleted'">{{ i18n.tsx._notification.exportOfXCompleted({ x: exportEntityName[notification.exportedEntity] }) }}</span> <MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA> @@ -107,6 +110,9 @@ SPDX-License-Identifier: AGPL-3.0-only <MkA v-else-if="notification.type === 'exportCompleted'" :class="$style.text" :to="`/my/drive/file/${notification.fileId}`"> {{ i18n.ts.showFile }} </MkA> + <MkA v-else-if="notification.type === 'createToken'" :class="$style.text" to="/settings/apps"> + <Mfm :text="i18n.tsx._notification.createTokenDescription({ text: i18n.ts.manageAccessTokens })"/> + </MkA> <template v-else-if="notification.type === 'follow'"> <span :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.youGotNewFollower }}</span> </template> @@ -357,6 +363,12 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification) pointer-events: none; } +.t_createToken { + padding: 3px; + background: var(--eventOther); + pointer-events: none; +} + .tail { flex: 1; min-width: 0; diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue index 12af8d93d7..1e7436bf9c 100644 --- a/packages/frontend/src/pages/settings/notifications.vue +++ b/packages/frontend/src/pages/settings/notifications.vue @@ -81,7 +81,7 @@ const $i = signinRequired(); const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted'] satisfies (typeof notificationTypes[number])[] as string[]; -const onlyOnOrOffNotificationTypes = ['app', 'achievementEarned', 'login'] satisfies (typeof notificationTypes[number])[] as string[]; +const onlyOnOrOffNotificationTypes = ['app', 'achievementEarned', 'login', 'createToken'] satisfies (typeof notificationTypes[number])[] as string[]; const allowButton = shallowRef<InstanceType<typeof MkPushNotificationAllowButton>>(); const pushRegistrationInServer = computed(() => allowButton.value?.pushRegistrationInServer); diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 313d0506fa..c7485c6c3d 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -4355,6 +4355,13 @@ export type components = { createdAt: string; /** @enum {string} */ type: 'login'; + } | { + /** Format: id */ + id: string; + /** Format: date-time */ + createdAt: string; + /** @enum {string} */ + type: 'createToken'; } | ({ /** Format: id */ id: string; @@ -19917,8 +19924,8 @@ export type operations = { untilId?: string; /** @default true */ markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; }; }; }; @@ -19985,8 +19992,8 @@ export type operations = { untilId?: string; /** @default true */ markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; }; }; }; |