firefish/packages/backend/src/server/api/common/read-messaging-message.ts

180 lines
5.1 KiB
TypeScript

import {
publishMainStream,
publishGroupMessagingStream,
} from "@/services/stream.js";
import { publishToChatStream, ChatEvent } from "backend-rs";
import { publishMessagingIndexStream } from "@/services/stream.js";
import { pushNotification } from "@/services/push-notification.js";
import type { User, IRemoteUser } from "@/models/entities/user.js";
import type { MessagingMessage } from "@/models/entities/messaging-message.js";
import { MessagingMessages, UserGroupJoinings, Users } from "@/models/index.js";
import { In } from "typeorm";
import { IdentifiableError } from "@/misc/identifiable-error.js";
import type { UserGroup } from "@/models/entities/user-group.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: User["id"],
otherpartyId: User["id"],
messageIds: MessagingMessage["id"][],
) {
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
publishToChatStream(otherpartyId, userId, ChatEvent.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: User["id"],
groupId: UserGroup["id"],
messageIds: MessagingMessage["id"][],
) {
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: MessagingMessage["id"][] = [];
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}')`) as any,
})
.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: { id: User["id"]; host: null },
recipient: IRemoteUser,
messages: MessagingMessage | MessagingMessage[],
) {
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);
}
}
}