2022-02-27 03:07:39 +01:00
|
|
|
import { publishMainStream, publishGroupMessagingStream } from '@/services/stream.js';
|
|
|
|
import { publishMessagingStream } from '@/services/stream.js';
|
|
|
|
import { publishMessagingIndexStream } from '@/services/stream.js';
|
2022-04-30 14:52:07 +02:00
|
|
|
import { pushNotification } from '@/services/push-notification.js';
|
2022-02-27 03:07:39 +01:00
|
|
|
import { User, IRemoteUser } from '@/models/entities/user.js';
|
|
|
|
import { MessagingMessage } from '@/models/entities/messaging-message.js';
|
|
|
|
import { MessagingMessages, UserGroupJoinings, Users } from '@/models/index.js';
|
2019-04-07 14:50:36 +02:00
|
|
|
import { In } from 'typeorm';
|
2022-02-27 03:07:39 +01:00
|
|
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|
|
|
import { 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';
|
2017-06-12 19:12:30 +02:00
|
|
|
|
|
|
|
/**
|
2018-07-20 07:16:02 +02:00
|
|
|
* Mark messages as read
|
2017-06-12 19:12:30 +02:00
|
|
|
*/
|
2019-05-18 13:36:33 +02:00
|
|
|
export async function readUserMessagingMessage(
|
2019-04-07 14:50:36 +02:00
|
|
|
userId: User['id'],
|
|
|
|
otherpartyId: User['id'],
|
|
|
|
messageIds: MessagingMessage['id'][]
|
2019-05-18 13:36:33 +02:00
|
|
|
) {
|
2019-04-07 14:50:36 +02:00
|
|
|
if (messageIds.length === 0) return;
|
2017-06-12 19:12:30 +02:00
|
|
|
|
2022-03-26 07:34:00 +01:00
|
|
|
const messages = await MessagingMessages.findBy({
|
2021-12-09 15:58:30 +01:00
|
|
|
id: In(messageIds),
|
2019-05-18 13:36:33 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
for (const message of messages) {
|
|
|
|
if (message.recipientId !== userId) {
|
|
|
|
throw new IdentifiableError('e140a4bf-49ce-4fb6-b67c-b78dadf6b52f', 'Access denied (user).');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 19:12:30 +02:00
|
|
|
// Update documents
|
2019-04-07 14:50:36 +02:00
|
|
|
await MessagingMessages.update({
|
|
|
|
id: In(messageIds),
|
2018-03-29 07:48:47 +02:00
|
|
|
userId: otherpartyId,
|
|
|
|
recipientId: userId,
|
2021-12-09 15:58:30 +01:00
|
|
|
isRead: false,
|
2017-06-12 19:12:30 +02:00
|
|
|
}, {
|
2021-12-09 15:58:30 +01:00
|
|
|
isRead: true,
|
2019-04-07 14:50:36 +02:00
|
|
|
});
|
2017-06-12 19:12:30 +02:00
|
|
|
|
|
|
|
// Publish event
|
2019-04-07 14:50:36 +02:00
|
|
|
publishMessagingStream(otherpartyId, userId, 'read', messageIds);
|
|
|
|
publishMessagingIndexStream(userId, 'read', messageIds);
|
2017-06-12 19:12:30 +02:00
|
|
|
|
2019-05-19 13:57:05 +02:00
|
|
|
if (!await Users.getHasUnreadMessagingMessage(userId)) {
|
2019-05-18 13:36:33 +02:00
|
|
|
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
|
|
|
publishMainStream(userId, 'readAllMessagingMessages');
|
2022-04-30 14:52:07 +02:00
|
|
|
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 });
|
|
|
|
}
|
2019-05-18 13:36:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark messages as read
|
|
|
|
*/
|
|
|
|
export async function readGroupMessagingMessage(
|
|
|
|
userId: User['id'],
|
|
|
|
groupId: UserGroup['id'],
|
|
|
|
messageIds: MessagingMessage['id'][]
|
|
|
|
) {
|
|
|
|
if (messageIds.length === 0) return;
|
|
|
|
|
|
|
|
// check joined
|
2022-03-26 07:34:00 +01:00
|
|
|
const joining = await UserGroupJoinings.findOneBy({
|
2019-05-18 13:36:33 +02:00
|
|
|
userId: userId,
|
2021-12-09 15:58:30 +01:00
|
|
|
userGroupId: groupId,
|
2019-05-18 13:36:33 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
if (joining == null) {
|
|
|
|
throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).');
|
|
|
|
}
|
|
|
|
|
2022-03-26 07:34:00 +01:00
|
|
|
const messages = await MessagingMessages.findBy({
|
2021-12-09 15:58:30 +01:00
|
|
|
id: In(messageIds),
|
2019-05-18 13:36:33 +02:00
|
|
|
});
|
|
|
|
|
2021-10-20 18:04:10 +02:00
|
|
|
const reads: MessagingMessage['id'][] = [];
|
2019-05-18 13:36:33 +02:00
|
|
|
|
|
|
|
for (const message of messages) {
|
|
|
|
if (message.userId === userId) continue;
|
|
|
|
if (message.reads.includes(userId)) continue;
|
|
|
|
|
|
|
|
// Update document
|
|
|
|
await MessagingMessages.createQueryBuilder().update()
|
|
|
|
.set({
|
2021-12-09 15:58:30 +01:00
|
|
|
reads: (() => `array_append("reads", '${joining.userId}')`) as any,
|
2019-05-18 13:36:33 +02:00
|
|
|
})
|
|
|
|
.where('id = :id', { id: message.id })
|
|
|
|
.execute();
|
|
|
|
|
|
|
|
reads.push(message.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Publish event
|
|
|
|
publishGroupMessagingStream(groupId, 'read', {
|
|
|
|
ids: reads,
|
2021-12-09 15:58:30 +01:00
|
|
|
userId: userId,
|
2019-04-07 14:50:36 +02:00
|
|
|
});
|
2019-05-18 13:36:33 +02:00
|
|
|
publishMessagingIndexStream(userId, 'read', reads);
|
2017-06-12 19:12:30 +02:00
|
|
|
|
2019-05-19 13:57:05 +02:00
|
|
|
if (!await Users.getHasUnreadMessagingMessage(userId)) {
|
2017-06-12 19:12:30 +02:00
|
|
|
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
2018-10-07 04:06:17 +02:00
|
|
|
publishMainStream(userId, 'readAllMessagingMessages');
|
2022-04-30 14:52:07 +02:00
|
|
|
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 });
|
|
|
|
}
|
2017-06-12 19:12:30 +02:00
|
|
|
}
|
2019-05-18 13:36:33 +02:00
|
|
|
}
|
2019-12-14 19:37:19 +01:00
|
|
|
|
2021-03-24 03:05:37 +01:00
|
|
|
export async function deliverReadActivity(user: { id: User['id']; host: null; }, recipient: IRemoteUser, messages: MessagingMessage | MessagingMessage[]) {
|
2019-12-14 19:37:19 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|