summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-03-25 15:25:43 +0900
committersyuilo <4439005+syuilo@users.noreply.github.com>2025-03-25 15:25:43 +0900
commit304d0eb83b6e10336ec319600f060f0a719d07b9 (patch)
tree4b030c55cbf7fb9183d2d6fffe5547decbdd8a29 /packages
parentBump version to 2025.3.2-beta.12 (diff)
downloadsharkey-304d0eb83b6e10336ec319600f060f0a719d07b9.tar.gz
sharkey-304d0eb83b6e10336ec319600f060f0a719d07b9.tar.bz2
sharkey-304d0eb83b6e10336ec319600f060f0a719d07b9.zip
enhance: チャットルームに招待されたときの通知を追加
Diffstat (limited to 'packages')
-rw-r--r--packages/backend/src/core/ChatService.ts6
-rw-r--r--packages/backend/src/core/entities/NotificationEntityService.ts23
-rw-r--r--packages/backend/src/models/Notification.ts6
-rw-r--r--packages/backend/src/models/json-schema/notification.ts15
-rw-r--r--packages/backend/src/models/json-schema/user.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/admin/show-user.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts1
-rw-r--r--packages/backend/src/types.ts2
-rw-r--r--packages/frontend-shared/js/const.ts1
-rw-r--r--packages/frontend/src/components/MkNotification.vue5
-rw-r--r--packages/misskey-js/etc/misskey-js.api.md2
-rw-r--r--packages/misskey-js/src/autogen/types.ts43
-rw-r--r--packages/misskey-js/src/consts.ts2
13 files changed, 95 insertions, 13 deletions
diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts
index 062ca96f17..4c010b2ef7 100644
--- a/packages/backend/src/core/ChatService.ts
+++ b/packages/backend/src/core/ChatService.ts
@@ -26,6 +26,7 @@ import { Packed } from '@/misc/json-schema.js';
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { emojiRegex } from '@/misc/emoji-regex.js';
+import { NotificationService } from '@/core/NotificationService.js';
const MAX_ROOM_MEMBERS = 30;
const MAX_REACTIONS_PER_MESSAGE = 100;
@@ -68,6 +69,7 @@ export class ChatService {
private apRendererService: ApRendererService,
private queueService: QueueService,
private pushNotificationService: PushNotificationService,
+ private notificationService: NotificationService,
private userBlockingService: UserBlockingService,
private queryService: QueryService,
private roleService: RoleService,
@@ -544,6 +546,10 @@ export class ChatService {
const created = await this.chatRoomInvitationsRepository.insertOne(invitation);
+ this.notificationService.createNotification(inviteeId, 'chatRoomInvitationReceived', {
+ invitationId: invitation.id,
+ }, inviterId);
+
return created;
}
diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts
index dff6968f9c..d8b947839f 100644
--- a/packages/backend/src/core/entities/NotificationEntityService.ts
+++ b/packages/backend/src/core/entities/NotificationEntityService.ts
@@ -16,6 +16,7 @@ import { bindThis } from '@/decorators.js';
import { FilterUnionByProperty, groupedNotificationTypes } from '@/types.js';
import { CacheService } from '@/core/CacheService.js';
import { RoleEntityService } from './RoleEntityService.js';
+import { ChatEntityService } from './ChatEntityService.js';
import type { OnModuleInit } from '@nestjs/common';
import type { UserEntityService } from './UserEntityService.js';
import type { NoteEntityService } from './NoteEntityService.js';
@@ -27,6 +28,7 @@ export class NotificationEntityService implements OnModuleInit {
private userEntityService: UserEntityService;
private noteEntityService: NoteEntityService;
private roleEntityService: RoleEntityService;
+ private chatEntityService: ChatEntityService;
constructor(
private moduleRef: ModuleRef,
@@ -41,9 +43,6 @@ export class NotificationEntityService implements OnModuleInit {
private followRequestsRepository: FollowRequestsRepository,
private cacheService: CacheService,
-
- //private userEntityService: UserEntityService,
- //private noteEntityService: NoteEntityService,
) {
}
@@ -51,6 +50,7 @@ export class NotificationEntityService implements OnModuleInit {
this.userEntityService = this.moduleRef.get('UserEntityService');
this.noteEntityService = this.moduleRef.get('NoteEntityService');
this.roleEntityService = this.moduleRef.get('RoleEntityService');
+ this.chatEntityService = this.moduleRef.get('ChatEntityService');
}
/**
@@ -59,7 +59,6 @@ export class NotificationEntityService implements OnModuleInit {
async #packInternal <T extends MiNotification | MiGroupedNotification> (
src: T,
meId: MiUser['id'],
-
options: {
checkValidNotifier?: boolean;
},
@@ -92,7 +91,7 @@ export class NotificationEntityService implements OnModuleInit {
// if the user has been deleted, don't show this notification
if (needsUser && !userIfNeed) return null;
- // #region Grouped notifications
+ //#region Grouped notifications
if (notification.type === 'reaction:grouped') {
const reactions = (await Promise.all(notification.reactions.map(async reaction => {
const user = hint?.packedUsers != null
@@ -137,7 +136,7 @@ export class NotificationEntityService implements OnModuleInit {
users,
});
}
- // #endregion
+ //#endregion
const needsRole = notification.type === 'roleAssigned';
const role = needsRole ? await this.roleEntityService.pack(notification.roleId) : undefined;
@@ -146,6 +145,13 @@ export class NotificationEntityService implements OnModuleInit {
return null;
}
+ const needsChatRoomInvitation = notification.type === 'chatRoomInvitationReceived';
+ const chatRoomInvitation = needsChatRoomInvitation ? await this.chatEntityService.packRoomInvitation(notification.invitationId, { id: meId }) : undefined;
+ // if the invitation has been deleted, don't show this notification
+ if (needsChatRoomInvitation && !chatRoomInvitation) {
+ return null;
+ }
+
return await awaitAll({
id: notification.id,
createdAt: new Date(notification.createdAt).toISOString(),
@@ -159,6 +165,9 @@ export class NotificationEntityService implements OnModuleInit {
...(notification.type === 'roleAssigned' ? {
role: role,
} : {}),
+ ...(notification.type === 'chatRoomInvitationReceived' ? {
+ invitation: chatRoomInvitation,
+ } : {}),
...(notification.type === 'followRequestAccepted' ? {
message: notification.message,
} : {}),
@@ -236,7 +245,7 @@ export class NotificationEntityService implements OnModuleInit {
public async pack(
src: MiNotification | MiGroupedNotification,
meId: MiUser['id'],
-
+
options: {
checkValidNotifier?: boolean;
},
diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts
index 5772ace338..5764a307b0 100644
--- a/packages/backend/src/models/Notification.ts
+++ b/packages/backend/src/models/Notification.ts
@@ -76,6 +76,12 @@ export type MiNotification = {
createdAt: string;
roleId: MiRole['id'];
} | {
+ type: 'chatRoomInvitationReceived';
+ id: string;
+ createdAt: string;
+ notifierId: MiUser['id'];
+ invitationId: string;
+} | {
type: 'achievementEarned';
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 1638b2b3c7..7f23d2d6a1 100644
--- a/packages/backend/src/models/json-schema/notification.ts
+++ b/packages/backend/src/models/json-schema/notification.ts
@@ -294,6 +294,21 @@ export const packedNotificationSchema = {
type: {
type: 'string',
optional: false, nullable: false,
+ enum: ['chatRoomInvitationReceived'],
+ },
+ invitation: {
+ type: 'object',
+ ref: 'ChatRoomInvitation',
+ optional: false, nullable: false,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
enum: ['achievementEarned'],
},
achievement: {
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index b10430782b..0094f25e34 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -608,6 +608,7 @@ export const packedMeDetailedOnlySchema = {
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
roleAssigned: { optional: true, ...notificationRecieveConfig },
+ chatRoomInvitationReceived: { optional: true, ...notificationRecieveConfig },
achievementEarned: { optional: true, ...notificationRecieveConfig },
app: { optional: true, ...notificationRecieveConfig },
test: { optional: true, ...notificationRecieveConfig },
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 655bd32bce..1ba6853dbe 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts
@@ -106,6 +106,7 @@ export const meta = {
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
roleAssigned: { optional: true, ...notificationRecieveConfig },
+ chatRoomInvitationReceived: { optional: true, ...notificationRecieveConfig },
achievementEarned: { optional: true, ...notificationRecieveConfig },
app: { optional: true, ...notificationRecieveConfig },
test: { 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 baf397bf06..082d97f5d4 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -212,6 +212,7 @@ export const paramDef = {
receiveFollowRequest: notificationRecieveConfig,
followRequestAccepted: notificationRecieveConfig,
roleAssigned: notificationRecieveConfig,
+ chatRoomInvitationReceived: notificationRecieveConfig,
achievementEarned: notificationRecieveConfig,
app: notificationRecieveConfig,
test: notificationRecieveConfig,
diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts
index c6b1035554..4e215c93c6 100644
--- a/packages/backend/src/types.ts
+++ b/packages/backend/src/types.ts
@@ -15,6 +15,7 @@
* receiveFollowRequest - フォローリクエストされた
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
* roleAssigned - ロールが付与された
+ * chatRoomInvitationReceived - チャットルームに招待された
* achievementEarned - 実績を獲得
* exportCompleted - エクスポートが完了
* login - ログイン
@@ -34,6 +35,7 @@ export const notificationTypes = [
'receiveFollowRequest',
'followRequestAccepted',
'roleAssigned',
+ 'chatRoomInvitationReceived',
'achievementEarned',
'exportCompleted',
'login',
diff --git a/packages/frontend-shared/js/const.ts b/packages/frontend-shared/js/const.ts
index 0241446784..fa60476b69 100644
--- a/packages/frontend-shared/js/const.ts
+++ b/packages/frontend-shared/js/const.ts
@@ -66,6 +66,7 @@ export const notificationTypes = [
'receiveFollowRequest',
'followRequestAccepted',
'roleAssigned',
+ 'chatRoomInvitationReceived',
'achievementEarned',
'exportCompleted',
'login',
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index 2824701579..c2e8b8e2fe 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -43,6 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<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>
+ <i v-else-if="notification.type === 'chatRoomInvitationReceived'" class="ti ti-messages"></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 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</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 === 'chatRoomInvitationReceived'">{{ i18n.ts._notification.chatRoomInvitationReceived }}</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>
@@ -104,6 +106,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else-if="notification.type === 'roleAssigned'" :class="$style.text">
{{ notification.role.name }}
</div>
+ <div v-else-if="notification.type === 'chatRoomInvitationReceived'" :class="$style.text">
+ {{ notification.invitation.room.name }}
+ </div>
<MkA v-else-if="notification.type === 'achievementEarned'" :class="$style.text" to="/my/achievements">
{{ i18n.ts._achievements._types['_' + notification.achievement].title }}
</MkA>
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 8610a21304..7e73b64bb0 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -3040,7 +3040,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", "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", "chatRoomInvitationReceived", "achievementEarned"];
// @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 3acef22101..3b52a70ccf 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4201,6 +4201,15 @@ export type components = {
/** Format: misskey:id */
userListId: string;
}]>;
+ chatRoomInvitationReceived?: OneOf<[{
+ /** @enum {string} */
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
+ }, {
+ /** @enum {string} */
+ type: 'list';
+ /** Format: misskey:id */
+ userListId: string;
+ }]>;
achievementEarned?: OneOf<[{
/** @enum {string} */
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
@@ -4538,6 +4547,14 @@ export type components = {
/** @enum {string} */
type: 'roleAssigned';
role: components['schemas']['Role'];
+ } | {
+ /** Format: id */
+ id: string;
+ /** Format: date-time */
+ createdAt: string;
+ /** @enum {string} */
+ type: 'chatRoomInvitationReceived';
+ invitation: components['schemas']['ChatRoomInvitation'];
} | ({
/** Format: id */
id: string;
@@ -10084,6 +10101,15 @@ export type operations = {
/** Format: misskey:id */
userListId: string;
}]>;
+ chatRoomInvitationReceived?: OneOf<[{
+ /** @enum {string} */
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
+ }, {
+ /** @enum {string} */
+ type: 'list';
+ /** Format: misskey:id */
+ userListId: string;
+ }]>;
achievementEarned?: OneOf<[{
/** @enum {string} */
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
@@ -21573,8 +21599,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' | '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')[];
+ includeTypes?: ('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' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
};
};
};
@@ -21641,8 +21667,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' | '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')[];
+ includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[];
+ excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[];
};
};
};
@@ -22738,6 +22764,15 @@ export type operations = {
/** Format: misskey:id */
userListId: string;
}]>;
+ chatRoomInvitationReceived?: OneOf<[{
+ /** @enum {string} */
+ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
+ }, {
+ /** @enum {string} */
+ type: 'list';
+ /** Format: misskey:id */
+ userListId: string;
+ }]>;
achievementEarned?: OneOf<[{
/** @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 9d0fe5e781..9a39e619b7 100644
--- a/packages/misskey-js/src/consts.ts
+++ b/packages/misskey-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', 'chatRoomInvitationReceived', 'achievementEarned'] as const;
export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const;