summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/ChatService.ts
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-03-25 16:09:19 +0900
committersyuilo <4439005+syuilo@users.noreply.github.com>2025-03-25 16:09:19 +0900
commit98554579eafd2765644c9b3ff37d33a26b6e5ceb (patch)
tree638b04c90ab1ddbb498d84e4fdac7b046ddb89c3 /packages/backend/src/core/ChatService.ts
parentfollow up of a01ae38a07f949cbcd5ce555cd90e8570bb985cc (diff)
downloadsharkey-98554579eafd2765644c9b3ff37d33a26b6e5ceb.tar.gz
sharkey-98554579eafd2765644c9b3ff37d33a26b6e5ceb.tar.bz2
sharkey-98554579eafd2765644c9b3ff37d33a26b6e5ceb.zip
enhance: チャットのリアクションを削除できるように
Diffstat (limited to 'packages/backend/src/core/ChatService.ts')
-rw-r--r--packages/backend/src/core/ChatService.ts76
1 files changed, 61 insertions, 15 deletions
diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts
index 6884fdfdb6..32f7896cdd 100644
--- a/packages/backend/src/core/ChatService.ts
+++ b/packages/backend/src/core/ChatService.ts
@@ -33,6 +33,20 @@ const MAX_ROOM_MEMBERS = 30;
const MAX_REACTIONS_PER_MESSAGE = 100;
const isCustomEmojiRegexp = /^:([\w+-]+)(?:@\.)?:$/;
+// TODO: ReactionServiceのやつと共通化
+function normalizeEmojiString(x: string) {
+ const match = emojiRegex.exec(x);
+ if (match) {
+ // 合字を含む1つの絵文字
+ const unicode = match[0];
+
+ // 異体字セレクタ除去
+ return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, '');
+ } else {
+ throw new Error('invalid emoji');
+ }
+}
+
@Injectable()
export class ChatService {
constructor(
@@ -751,24 +765,10 @@ export class ChatService {
public async react(messageId: MiChatMessage['id'], userId: MiUser['id'], reaction_: string) {
let reaction;
- // TODO: ReactionServiceのやつと共通化
- function normalize(x: string) {
- const match = emojiRegex.exec(x);
- if (match) {
- // 合字を含む1つの絵文字
- const unicode = match[0];
-
- // 異体字セレクタ除去
- return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, '');
- } else {
- throw new Error('invalid emoji');
- }
- }
-
const custom = reaction_.match(isCustomEmojiRegexp);
if (custom == null) {
- reaction = normalize(reaction_);
+ reaction = normalizeEmojiString(reaction_);
} else {
const name = custom[1];
const emoji = (await this.customEmojiService.localEmojisCache.fetch()).get(name);
@@ -828,6 +828,52 @@ export class ChatService {
}
@bindThis
+ public async unreact(messageId: MiChatMessage['id'], userId: MiUser['id'], reaction_: string) {
+ let reaction;
+
+ const custom = reaction_.match(isCustomEmojiRegexp);
+
+ if (custom == null) {
+ reaction = normalizeEmojiString(reaction_);
+ } else { // 削除されたカスタム絵文字のリアクションを削除したいかもしれないので絵文字の存在チェックはする必要なし
+ const name = custom[1];
+ reaction = `:${name}:`;
+ }
+
+ // NOTE: 自分のリアクションを(あれば)削除するだけなので諸々の権限チェックは必要なし
+
+ const message = await this.chatMessagesRepository.findOneByOrFail({ id: messageId });
+
+ const room = message.toRoomId ? await this.chatRoomsRepository.findOneByOrFail({ id: message.toRoomId }) : null;
+
+ await this.chatMessagesRepository.createQueryBuilder().update()
+ .set({
+ reactions: () => `array_remove("reactions", '${userId}/${reaction}')`,
+ })
+ .where('id = :id', { id: message.id })
+ .execute();
+
+ // TODO: 実際に削除が行われたときのみイベントを発行する
+
+ if (room) {
+ this.globalEventService.publishChatRoomStream(room.id, 'unreact', {
+ messageId: message.id,
+ user: await this.userEntityService.pack(userId),
+ reaction,
+ });
+ } else {
+ this.globalEventService.publishChatUserStream(message.fromUserId, message.toUserId!, 'unreact', {
+ messageId: message.id,
+ reaction,
+ });
+ this.globalEventService.publishChatUserStream(message.toUserId!, message.fromUserId, 'unreact', {
+ messageId: message.id,
+ reaction,
+ });
+ }
+ }
+
+ @bindThis
public async getMyMemberships(userId: MiUser['id'], limit: number, sinceId?: MiChatRoomMembership['id'] | null, untilId?: MiChatRoomMembership['id'] | null) {
const query = this.queryService.makePaginationQuery(this.chatRoomMembershipsRepository.createQueryBuilder('membership'), sinceId, untilId)
.where('membership.userId = :userId', { userId });