import { publishMainStream, publishGroupMessagingStream } from "../../../services/stream.js"; import { publishMessagingStream } from "../../../services/stream.js"; import { publishMessagingIndexStream } from "../../../services/stream.js"; import { pushNotification } from "../../../services/push-notification.js"; import { MessagingMessages, UserGroupJoinings, Users } from "../../../models/index.js"; import { In } from "typeorm"; import { IdentifiableError } from "../../../misc/identifiable-error.js"; import { toArray } from "../../../prelude/array.js"; import { renderReadActivity } from "../../../remote/activitypub/renderer/read.js"; import { renderActivity } from "../../../remote/activitypub/renderer/index.js"; import { deliver } from "../../../queue/index.js"; import orderedCollection from "../../../remote/activitypub/renderer/ordered-collection.js"; /** * Mark messages as read */ export async function readUserMessagingMessage(userId, otherpartyId, messageIds) { if (messageIds.length === 0) return; const messages = await MessagingMessages.findBy({ id: In(messageIds) }); for (const message of messages){ if (message.recipientId !== userId) { throw new IdentifiableError("e140a4bf-49ce-4fb6-b67c-b78dadf6b52f", "Access denied (user)."); } } // Update documents await MessagingMessages.update({ id: In(messageIds), userId: otherpartyId, recipientId: userId, isRead: false }, { isRead: true }); // Publish event publishMessagingStream(otherpartyId, userId, "read", messageIds); publishMessagingIndexStream(userId, "read", messageIds); if (!await Users.getHasUnreadMessagingMessage(userId)) { // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 publishMainStream(userId, "readAllMessagingMessages"); pushNotification(userId, "readAllMessagingMessages", undefined); } else { // そのユーザーとのメッセージで未読がなければイベント発行 const count = await MessagingMessages.count({ where: { userId: otherpartyId, recipientId: userId, isRead: false }, take: 1 }); if (!count) { pushNotification(userId, "readAllMessagingMessagesOfARoom", { userId: otherpartyId }); } } } /** * Mark messages as read */ export async function readGroupMessagingMessage(userId, groupId, messageIds) { if (messageIds.length === 0) return; // check joined const joining = await UserGroupJoinings.findOneBy({ userId: userId, userGroupId: groupId }); if (joining == null) { throw new IdentifiableError("930a270c-714a-46b2-b776-ad27276dc569", "Access denied (group)."); } const messages = await MessagingMessages.findBy({ id: In(messageIds) }); const reads = []; for (const message of messages){ if (message.userId === userId) continue; if (message.reads.includes(userId)) continue; // Update document await MessagingMessages.createQueryBuilder().update().set({ reads: ()=>`array_append("reads", '${joining.userId}')` }).where("id = :id", { id: message.id }).execute(); reads.push(message.id); } // Publish event publishGroupMessagingStream(groupId, "read", { ids: reads, userId: userId }); publishMessagingIndexStream(userId, "read", reads); if (!await Users.getHasUnreadMessagingMessage(userId)) { // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 publishMainStream(userId, "readAllMessagingMessages"); pushNotification(userId, "readAllMessagingMessages", undefined); } else { // そのグループにおいて未読がなければイベント発行 const unreadExist = await MessagingMessages.createQueryBuilder("message").where("message.groupId = :groupId", { groupId: groupId }).andWhere("message.userId != :userId", { userId: userId }).andWhere("NOT (:userId = ANY(message.reads))", { userId: userId }).andWhere("message.createdAt > :joinedAt", { joinedAt: joining.createdAt }) // 自分が加入する前の会話については、未読扱いしない .getOne().then((x)=>x != null); if (!unreadExist) { pushNotification(userId, "readAllMessagingMessagesOfARoom", { groupId }); } } } export async function deliverReadActivity(user, recipient, messages) { messages = toArray(messages).filter((x)=>x.uri); const contents = messages.map((x)=>renderReadActivity(user, x)); if (contents.length > 1) { const collection = orderedCollection(null, contents.length, undefined, undefined, contents); deliver(user, renderActivity(collection), recipient.inbox); } else { for (const content of contents){ deliver(user, renderActivity(content), recipient.inbox); } } }