mirror of
https://github.com/paricafe/misskey.git
synced 2025-03-31 14:29:28 -05:00
enhance: チャットルームに招待されたときの通知を追加
This commit is contained in:
parent
2fc3baa988
commit
304d0eb83b
15 changed files with 105 additions and 13 deletions
locales
packages
backend/src
frontend-shared/js
frontend/src/components
misskey-js
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
|
@ -9883,6 +9883,10 @@ export interface Locale extends ILocale {
|
|||
* ロールが付与されました
|
||||
*/
|
||||
"roleAssigned": string;
|
||||
/**
|
||||
* チャットルームへ招待されました
|
||||
*/
|
||||
"chatRoomInvitationReceived": string;
|
||||
/**
|
||||
* プッシュ通知の更新をしました
|
||||
*/
|
||||
|
@ -9992,6 +9996,10 @@ export interface Locale extends ILocale {
|
|||
* ロールが付与された
|
||||
*/
|
||||
"roleAssigned": string;
|
||||
/**
|
||||
* チャットルームへ招待された
|
||||
*/
|
||||
"chatRoomInvitationReceived": string;
|
||||
/**
|
||||
* 実績の獲得
|
||||
*/
|
||||
|
|
|
@ -2612,6 +2612,7 @@ _notification:
|
|||
newNote: "新しい投稿"
|
||||
unreadAntennaNote: "アンテナ {name}"
|
||||
roleAssigned: "ロールが付与されました"
|
||||
chatRoomInvitationReceived: "チャットルームへ招待されました"
|
||||
emptyPushNotificationMessage: "プッシュ通知の更新をしました"
|
||||
achievementEarned: "実績を獲得"
|
||||
testNotification: "通知テスト"
|
||||
|
@ -2641,6 +2642,7 @@ _notification:
|
|||
receiveFollowRequest: "フォロー申請を受け取った"
|
||||
followRequestAccepted: "フォローが受理された"
|
||||
roleAssigned: "ロールが付与された"
|
||||
chatRoomInvitationReceived: "チャットルームへ招待された"
|
||||
achievementEarned: "実績の獲得"
|
||||
exportCompleted: "エクスポートが完了した"
|
||||
login: "ログイン"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -75,6 +75,12 @@ export type MiNotification = {
|
|||
id: string;
|
||||
createdAt: string;
|
||||
roleId: MiRole['id'];
|
||||
} | {
|
||||
type: 'chatRoomInvitationReceived';
|
||||
id: string;
|
||||
createdAt: string;
|
||||
notifierId: MiUser['id'];
|
||||
invitationId: string;
|
||||
} | {
|
||||
type: 'achievementEarned';
|
||||
id: string;
|
||||
|
|
|
@ -287,6 +287,21 @@ export const packedNotificationSchema = {
|
|||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['chatRoomInvitationReceived'],
|
||||
},
|
||||
invitation: {
|
||||
type: 'object',
|
||||
ref: 'ChatRoomInvitation',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -212,6 +212,7 @@ export const paramDef = {
|
|||
receiveFollowRequest: notificationRecieveConfig,
|
||||
followRequestAccepted: notificationRecieveConfig,
|
||||
roleAssigned: notificationRecieveConfig,
|
||||
chatRoomInvitationReceived: notificationRecieveConfig,
|
||||
achievementEarned: notificationRecieveConfig,
|
||||
app: notificationRecieveConfig,
|
||||
test: notificationRecieveConfig,
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -66,6 +66,7 @@ export const notificationTypes = [
|
|||
'receiveFollowRequest',
|
||||
'followRequestAccepted',
|
||||
'roleAssigned',
|
||||
'chatRoomInvitationReceived',
|
||||
'achievementEarned',
|
||||
'exportCompleted',
|
||||
'login',
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue