wip
This commit is contained in:
		@@ -54,14 +54,14 @@ export class ChatService {
 | 
				
			|||||||
	public async createMessage(params: {
 | 
						public async createMessage(params: {
 | 
				
			||||||
		fromUser: { id: MiUser['id']; host: MiUser['host']; };
 | 
							fromUser: { id: MiUser['id']; host: MiUser['host']; };
 | 
				
			||||||
		toUser?: MiUser | null;
 | 
							toUser?: MiUser | null;
 | 
				
			||||||
		//toGroup?: MiUserGroup | null;
 | 
							//toRoom?: MiUserRoom | null;
 | 
				
			||||||
		text?: string | null;
 | 
							text?: string | null;
 | 
				
			||||||
		file?: MiDriveFile | null;
 | 
							file?: MiDriveFile | null;
 | 
				
			||||||
		uri?: string | null;
 | 
							uri?: string | null;
 | 
				
			||||||
	}) {
 | 
						}) {
 | 
				
			||||||
		const { fromUser, toUser /*toGroup*/ } = params;
 | 
							const { fromUser, toUser /*toRoom*/ } = params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (toUser == null /*&& toGroup == null*/) {
 | 
							if (toUser == null /*&& toRoom == null*/) {
 | 
				
			||||||
			throw new Error('recipient is required');
 | 
								throw new Error('recipient is required');
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,7 +76,7 @@ export class ChatService {
 | 
				
			|||||||
			id: this.idService.gen(),
 | 
								id: this.idService.gen(),
 | 
				
			||||||
			fromUserId: fromUser.id,
 | 
								fromUserId: fromUser.id,
 | 
				
			||||||
			toUserId: toUser ? toUser.id : null,
 | 
								toUserId: toUser ? toUser.id : null,
 | 
				
			||||||
			//toGroupId: recipientGroup ? recipientGroup.id : null,
 | 
								//toRoomId: recipientRoom ? recipientRoom.id : null,
 | 
				
			||||||
			text: params.text ? params.text.trim() : null,
 | 
								text: params.text ? params.text.trim() : null,
 | 
				
			||||||
			fileId: params.file ? params.file.id : null,
 | 
								fileId: params.file ? params.file.id : null,
 | 
				
			||||||
			reads: [],
 | 
								reads: [],
 | 
				
			||||||
@@ -102,12 +102,12 @@ export class ChatService {
 | 
				
			|||||||
				// 相手のストリーム
 | 
									// 相手のストリーム
 | 
				
			||||||
				this.globalEventService.publishChatStream(toUser.id, fromUser.id, 'message', packedMessage);
 | 
									this.globalEventService.publishChatStream(toUser.id, fromUser.id, 'message', packedMessage);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}/* else if (toGroup) {
 | 
							}/* else if (toRoom) {
 | 
				
			||||||
			// グループのストリーム
 | 
								// グループのストリーム
 | 
				
			||||||
			this.globalEventService.publishGroupChatStream(toGroup.id, 'message', messageObj);
 | 
								this.globalEventService.publishRoomChatStream(toRoom.id, 'message', messageObj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// メンバーのストリーム
 | 
								// メンバーのストリーム
 | 
				
			||||||
			const joinings = await this.userGroupJoiningsRepository.findBy({ userGroupId: toGroup.id });
 | 
								const joinings = await this.userRoomJoiningsRepository.findBy({ userRoomId: toRoom.id });
 | 
				
			||||||
			for (const joining of joinings) {
 | 
								for (const joining of joinings) {
 | 
				
			||||||
				this.globalEventService.publishChatIndexStream(joining.userId, 'message', messageObj);
 | 
									this.globalEventService.publishChatIndexStream(joining.userId, 'message', messageObj);
 | 
				
			||||||
				this.globalEventService.publishMainStream(joining.userId, 'chatMessage', messageObj);
 | 
									this.globalEventService.publishMainStream(joining.userId, 'chatMessage', messageObj);
 | 
				
			||||||
@@ -124,8 +124,8 @@ export class ChatService {
 | 
				
			|||||||
				const packedMessageForTo = await this.chatMessageEntityService.pack(inserted, toUser);
 | 
									const packedMessageForTo = await this.chatMessageEntityService.pack(inserted, toUser);
 | 
				
			||||||
				this.globalEventService.publishMainStream(toUser.id, 'newChatMessage', packedMessageForTo);
 | 
									this.globalEventService.publishMainStream(toUser.id, 'newChatMessage', packedMessageForTo);
 | 
				
			||||||
				this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo);
 | 
									this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo);
 | 
				
			||||||
			}/* else if (toGroup) {
 | 
								}/* else if (toRoom) {
 | 
				
			||||||
				const joinings = await this.userGroupJoiningsRepository.findBy({ userGroupId: toGroup.id, userId: Not(fromUser.id) });
 | 
									const joinings = await this.userRoomJoiningsRepository.findBy({ userRoomId: toRoom.id, userId: Not(fromUser.id) });
 | 
				
			||||||
				for (const joining of joinings) {
 | 
									for (const joining of joinings) {
 | 
				
			||||||
					if (freshMessage.reads.includes(joining.userId)) return; // 既読
 | 
										if (freshMessage.reads.includes(joining.userId)) return; // 既読
 | 
				
			||||||
					this.globalEventService.publishMainStream(joining.userId, 'newChatMessage', messageObj);
 | 
										this.globalEventService.publishMainStream(joining.userId, 'newChatMessage', messageObj);
 | 
				
			||||||
@@ -186,28 +186,28 @@ export class ChatService {
 | 
				
			|||||||
				const activity = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), fromUser));
 | 
									const activity = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), fromUser));
 | 
				
			||||||
				this.queueService.deliver(fromUser, activity, toUser.inbox);
 | 
									this.queueService.deliver(fromUser, activity, toUser.inbox);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}/* else if (message.groupId) {
 | 
							}/* else if (message.roomId) {
 | 
				
			||||||
			this.globalEventService.publishGroupChatStream(message.groupId, 'deleted', message.id);
 | 
								this.globalEventService.publishRoomChatStream(message.roomId, 'deleted', message.id);
 | 
				
			||||||
		}*/
 | 
							}*/
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	@bindThis
 | 
						@bindThis
 | 
				
			||||||
	public async readGroupChatMessage(
 | 
						public async readRoomChatMessage(
 | 
				
			||||||
		userId: MiUser['id'],
 | 
							userId: MiUser['id'],
 | 
				
			||||||
		groupId: MiUserGroup['id'],
 | 
							roomId: MiUserRoom['id'],
 | 
				
			||||||
		messageIds: MiChatMessage['id'][],
 | 
							messageIds: MiChatMessage['id'][],
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		if (messageIds.length === 0) return;
 | 
							if (messageIds.length === 0) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// check joined
 | 
							// check joined
 | 
				
			||||||
		const joining = await this.userGroupJoiningsRepository.findOneBy({
 | 
							const joining = await this.userRoomJoiningsRepository.findOneBy({
 | 
				
			||||||
			userId: userId,
 | 
								userId: userId,
 | 
				
			||||||
			userGroupId: groupId,
 | 
								userRoomId: roomId,
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (joining == null) {
 | 
							if (joining == null) {
 | 
				
			||||||
			throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).');
 | 
								throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (room).');
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const messages = await this.chatMessagesRepository.findBy({
 | 
							const messages = await this.chatMessagesRepository.findBy({
 | 
				
			||||||
@@ -232,7 +232,7 @@ export class ChatService {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Publish event
 | 
							// Publish event
 | 
				
			||||||
		this.globalEventService.publishGroupChatStream(groupId, 'read', {
 | 
							this.globalEventService.publishRoomChatStream(roomId, 'read', {
 | 
				
			||||||
			ids: reads,
 | 
								ids: reads,
 | 
				
			||||||
			userId: userId,
 | 
								userId: userId,
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
@@ -245,14 +245,14 @@ export class ChatService {
 | 
				
			|||||||
		} else {
 | 
							} else {
 | 
				
			||||||
		// そのグループにおいて未読がなければイベント発行
 | 
							// そのグループにおいて未読がなければイベント発行
 | 
				
			||||||
			const unreadExist = await this.chatMessagesRepository.createQueryBuilder('message')
 | 
								const unreadExist = await this.chatMessagesRepository.createQueryBuilder('message')
 | 
				
			||||||
				.where('message.groupId = :groupId', { groupId: groupId })
 | 
									.where('message.roomId = :roomId', { roomId: roomId })
 | 
				
			||||||
				.andWhere('message.userId != :userId', { userId: userId })
 | 
									.andWhere('message.userId != :userId', { userId: userId })
 | 
				
			||||||
				.andWhere('NOT (:userId = ANY(message.reads))', { userId: userId })
 | 
									.andWhere('NOT (:userId = ANY(message.reads))', { userId: userId })
 | 
				
			||||||
				.andWhere('message.createdAt > :joinedAt', { joinedAt: joining.createdAt }) // 自分が加入する前の会話については、未読扱いしない
 | 
									.andWhere('message.createdAt > :joinedAt', { joinedAt: joining.createdAt }) // 自分が加入する前の会話については、未読扱いしない
 | 
				
			||||||
				.getOne().then(x => x != null);
 | 
									.getOne().then(x => x != null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!unreadExist) {
 | 
								if (!unreadExist) {
 | 
				
			||||||
				this.pushNotificationService.pushNotification(userId, 'readAllChatMessagesOfARoom', { groupId });
 | 
									this.pushNotificationService.pushNotification(userId, 'readAllChatMessagesOfARoom', { roomId });
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -300,7 +300,7 @@ export class ChatService {
 | 
				
			|||||||
						.where('message.fromUserId = :meId', { meId: meId })
 | 
											.where('message.fromUserId = :meId', { meId: meId })
 | 
				
			||||||
						.orWhere('message.toUserId = :meId', { meId: meId });
 | 
											.orWhere('message.toUserId = :meId', { meId: meId });
 | 
				
			||||||
				}))
 | 
									}))
 | 
				
			||||||
				.andWhere('message.groupId IS NULL')
 | 
									.andWhere('message.roomId IS NULL')
 | 
				
			||||||
				.andWhere(`message.fromUserId NOT IN (${ mutingQuery.getQuery() })`)
 | 
									.andWhere(`message.fromUserId NOT IN (${ mutingQuery.getQuery() })`)
 | 
				
			||||||
				.andWhere(`message.toUserId NOT IN (${ mutingQuery.getQuery() })`);
 | 
									.andWhere(`message.toUserId NOT IN (${ mutingQuery.getQuery() })`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -324,27 +324,27 @@ export class ChatService {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@bindThis
 | 
						@bindThis
 | 
				
			||||||
	public async groupHistory(meId: MiUser['id'], limit: number) {
 | 
						public async roomHistory(meId: MiUser['id'], limit: number) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		const groups = await this.userGroupJoiningsRepository.findBy({
 | 
							const rooms = await this.userRoomJoiningsRepository.findBy({
 | 
				
			||||||
			userId: meId,
 | 
								userId: meId,
 | 
				
			||||||
		}).then(xs => xs.map(x => x.userGroupId));
 | 
							}).then(xs => xs.map(x => x.userRoomId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (groups.length === 0) {
 | 
							if (rooms.length === 0) {
 | 
				
			||||||
			return [];
 | 
								return [];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const history: MiChatMessage[] = [];
 | 
							const history: MiChatMessage[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (let i = 0; i < limit; i++) {
 | 
							for (let i = 0; i < limit; i++) {
 | 
				
			||||||
			const found = history.map(m => m.groupId!);
 | 
								const found = history.map(m => m.roomId!);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const query = this.chatMessagesRepository.createQueryBuilder('message')
 | 
								const query = this.chatMessagesRepository.createQueryBuilder('message')
 | 
				
			||||||
				.orderBy('message.id', 'DESC')
 | 
									.orderBy('message.id', 'DESC')
 | 
				
			||||||
				.where('message.groupId IN (:...groups)', { groups: groups });
 | 
									.where('message.roomId IN (:...rooms)', { rooms: rooms });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (found.length > 0) {
 | 
								if (found.length > 0) {
 | 
				
			||||||
				query.andWhere('message.groupId NOT IN (:...found)', { found: found });
 | 
									query.andWhere('message.roomId NOT IN (:...found)', { found: found });
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const message = await query.getOne();
 | 
								const message = await query.getOne();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typ
 | 
				
			|||||||
import { id } from './util/id.js';
 | 
					import { id } from './util/id.js';
 | 
				
			||||||
import { MiUser } from './User.js';
 | 
					import { MiUser } from './User.js';
 | 
				
			||||||
import { MiDriveFile } from './DriveFile.js';
 | 
					import { MiDriveFile } from './DriveFile.js';
 | 
				
			||||||
 | 
					import { MiChatRoom } from './ChatRoom.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Entity('chat_message')
 | 
					@Entity('chat_message')
 | 
				
			||||||
export class MiChatMessage {
 | 
					export class MiChatMessage {
 | 
				
			||||||
@@ -37,19 +38,17 @@ export class MiChatMessage {
 | 
				
			|||||||
	@JoinColumn()
 | 
						@JoinColumn()
 | 
				
			||||||
	public toUser: MiUser | null;
 | 
						public toUser: MiUser | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	@Index()
 | 
						@Index()
 | 
				
			||||||
	@Column({
 | 
						@Column({
 | 
				
			||||||
		...id(), nullable: true,
 | 
							...id(), nullable: true,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	public toGroupId: MiUserGroup['id'] | null;
 | 
						public toRoomId: MiChatRoom['id'] | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@ManyToOne(type => MiUserGroup, {
 | 
						@ManyToOne(type => MiChatRoom, {
 | 
				
			||||||
		onDelete: 'CASCADE',
 | 
							onDelete: 'CASCADE',
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	@JoinColumn()
 | 
						@JoinColumn()
 | 
				
			||||||
	public toGroup: MiUserGroup | null;
 | 
						public toRoom: MiChatRoom | null;
 | 
				
			||||||
	*/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Column('varchar', {
 | 
						@Column('varchar', {
 | 
				
			||||||
		length: 4096, nullable: true,
 | 
							length: 4096, nullable: true,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								packages/backend/src/models/ChatRoom.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/backend/src/models/ChatRoom.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * SPDX-FileCopyrightText: syuilo and misskey-project
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
 | 
				
			||||||
 | 
					import { id } from './util/id.js';
 | 
				
			||||||
 | 
					import { MiUser } from './User.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Entity('chat_room')
 | 
				
			||||||
 | 
					export class MiChatRoom {
 | 
				
			||||||
 | 
						@PrimaryColumn(id())
 | 
				
			||||||
 | 
						public id: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Column('varchar', {
 | 
				
			||||||
 | 
							length: 256,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						public name: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Index()
 | 
				
			||||||
 | 
						@Column({
 | 
				
			||||||
 | 
							...id(),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						public ownerId: MiUser['id'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@ManyToOne(type => MiUser, {
 | 
				
			||||||
 | 
							onDelete: 'CASCADE',
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						@JoinColumn()
 | 
				
			||||||
 | 
						public owner: MiUser | null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								packages/backend/src/models/ChatRoomMembership.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								packages/backend/src/models/ChatRoomMembership.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * SPDX-FileCopyrightText: syuilo and misskey-project
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
 | 
				
			||||||
 | 
					import { id } from './util/id.js';
 | 
				
			||||||
 | 
					import { MiUser } from './User.js';
 | 
				
			||||||
 | 
					import { MiChatRoom } from './ChatRoom.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Entity('chat_room_membership')
 | 
				
			||||||
 | 
					export class MiChatRoomMembership {
 | 
				
			||||||
 | 
						@PrimaryColumn(id())
 | 
				
			||||||
 | 
						public id: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Index()
 | 
				
			||||||
 | 
						@Column({
 | 
				
			||||||
 | 
							...id(),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						public userId: MiUser['id'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@ManyToOne(type => MiUser, {
 | 
				
			||||||
 | 
							onDelete: 'CASCADE',
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						@JoinColumn()
 | 
				
			||||||
 | 
						public user: MiUser | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Index()
 | 
				
			||||||
 | 
						@Column({
 | 
				
			||||||
 | 
							...id(),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						public roomId: MiChatRoom['id'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@ManyToOne(type => MiChatRoom, {
 | 
				
			||||||
 | 
							onDelete: 'CASCADE',
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						@JoinColumn()
 | 
				
			||||||
 | 
						public room: MiChatRoom | null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -76,6 +76,8 @@ import { MiFlash } from '@/models/Flash.js';
 | 
				
			|||||||
import { MiFlashLike } from '@/models/FlashLike.js';
 | 
					import { MiFlashLike } from '@/models/FlashLike.js';
 | 
				
			||||||
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
 | 
					import { MiUserListFavorite } from '@/models/UserListFavorite.js';
 | 
				
			||||||
import { MiChatMessage } from '@/models/ChatMessage.js';
 | 
					import { MiChatMessage } from '@/models/ChatMessage.js';
 | 
				
			||||||
 | 
					import { MiChatRoom } from '@/models/ChatRoom.js';
 | 
				
			||||||
 | 
					import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
 | 
				
			||||||
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
 | 
					import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
 | 
				
			||||||
import { MiReversiGame } from '@/models/ReversiGame.js';
 | 
					import { MiReversiGame } from '@/models/ReversiGame.js';
 | 
				
			||||||
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
 | 
					import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
 | 
				
			||||||
@@ -193,6 +195,8 @@ export {
 | 
				
			|||||||
	MiFlashLike,
 | 
						MiFlashLike,
 | 
				
			||||||
	MiUserMemo,
 | 
						MiUserMemo,
 | 
				
			||||||
	MiChatMessage,
 | 
						MiChatMessage,
 | 
				
			||||||
 | 
						MiChatRoom,
 | 
				
			||||||
 | 
						MiChatRoomMembership,
 | 
				
			||||||
	MiBubbleGameRecord,
 | 
						MiBubbleGameRecord,
 | 
				
			||||||
	MiReversiGame,
 | 
						MiReversiGame,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -266,5 +270,7 @@ export type FlashsRepository = Repository<MiFlash> & MiRepository<MiFlash>;
 | 
				
			|||||||
export type FlashLikesRepository = Repository<MiFlashLike> & MiRepository<MiFlashLike>;
 | 
					export type FlashLikesRepository = Repository<MiFlashLike> & MiRepository<MiFlashLike>;
 | 
				
			||||||
export type UserMemoRepository = Repository<MiUserMemo> & MiRepository<MiUserMemo>;
 | 
					export type UserMemoRepository = Repository<MiUserMemo> & MiRepository<MiUserMemo>;
 | 
				
			||||||
export type ChatMessagesRepository = Repository<MiChatMessage> & MiRepository<MiChatMessage>;
 | 
					export type ChatMessagesRepository = Repository<MiChatMessage> & MiRepository<MiChatMessage>;
 | 
				
			||||||
 | 
					export type ChatRoomsRepository = Repository<MiChatRoom> & MiRepository<MiChatRoom>;
 | 
				
			||||||
 | 
					export type ChatRoomMembershipsRepository = Repository<MiChatRoomMembership> & MiRepository<MiChatRoomMembership>;
 | 
				
			||||||
export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord> & MiRepository<MiBubbleGameRecord>;
 | 
					export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord> & MiRepository<MiBubbleGameRecord>;
 | 
				
			||||||
export type ReversiGamesRepository = Repository<MiReversiGame> & MiRepository<MiReversiGame>;
 | 
					export type ReversiGamesRepository = Repository<MiReversiGame> & MiRepository<MiReversiGame>;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,6 +77,8 @@ import { MiFlash } from '@/models/Flash.js';
 | 
				
			|||||||
import { MiFlashLike } from '@/models/FlashLike.js';
 | 
					import { MiFlashLike } from '@/models/FlashLike.js';
 | 
				
			||||||
import { MiUserMemo } from '@/models/UserMemo.js';
 | 
					import { MiUserMemo } from '@/models/UserMemo.js';
 | 
				
			||||||
import { MiChatMessage } from '@/models/ChatMessage.js';
 | 
					import { MiChatMessage } from '@/models/ChatMessage.js';
 | 
				
			||||||
 | 
					import { MiChatRoom } from '@/models/ChatRoom.js';
 | 
				
			||||||
 | 
					import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
 | 
				
			||||||
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
 | 
					import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
 | 
				
			||||||
import { MiReversiGame } from '@/models/ReversiGame.js';
 | 
					import { MiReversiGame } from '@/models/ReversiGame.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -238,6 +240,8 @@ export const entities = [
 | 
				
			|||||||
	MiFlashLike,
 | 
						MiFlashLike,
 | 
				
			||||||
	MiUserMemo,
 | 
						MiUserMemo,
 | 
				
			||||||
	MiChatMessage,
 | 
						MiChatMessage,
 | 
				
			||||||
 | 
						MiChatRoom,
 | 
				
			||||||
 | 
						MiChatRoomMembership,
 | 
				
			||||||
	MiBubbleGameRecord,
 | 
						MiBubbleGameRecord,
 | 
				
			||||||
	MiReversiGame,
 | 
						MiReversiGame,
 | 
				
			||||||
	...charts,
 | 
						...charts,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,15 +45,15 @@ export const meta = {
 | 
				
			|||||||
			id: '11795c64-40ea-4198-b06e-3c873ed9039d',
 | 
								id: '11795c64-40ea-4198-b06e-3c873ed9039d',
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		noSuchGroup: {
 | 
							noSuchRoom: {
 | 
				
			||||||
			message: 'No such group.',
 | 
								message: 'No such room.',
 | 
				
			||||||
			code: 'NO_SUCH_GROUP',
 | 
								code: 'NO_SUCH_ROOM',
 | 
				
			||||||
			id: 'c94e2a5d-06aa-4914-8fa6-6a42e73d6537',
 | 
								id: 'c94e2a5d-06aa-4914-8fa6-6a42e73d6537',
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		groupAccessDenied: {
 | 
							roomAccessDenied: {
 | 
				
			||||||
			message: 'You can not send messages to groups that you have not joined.',
 | 
								message: 'You can not send messages to rooms that you have not joined.',
 | 
				
			||||||
			code: 'GROUP_ACCESS_DENIED',
 | 
								code: 'ROOM_ACCESS_DENIED',
 | 
				
			||||||
			id: 'd96b3cca-5ad1-438b-ad8b-02f931308fbd',
 | 
								id: 'd96b3cca-5ad1-438b-ad8b-02f931308fbd',
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -130,22 +130,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			|||||||
					text: ps.text,
 | 
										text: ps.text,
 | 
				
			||||||
					file: file,
 | 
										file: file,
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			}/* else if (ps.groupId != null) {
 | 
								}/* else if (ps.roomId != null) {
 | 
				
			||||||
				// Fetch recipient (group)
 | 
									// Fetch recipient (room)
 | 
				
			||||||
				recipientGroup = await this.userGroupsRepository.findOneBy({ id: ps.groupId! });
 | 
									recipientRoom = await this.userRoomsRepository.findOneBy({ id: ps.roomId! });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (recipientGroup == null) {
 | 
									if (recipientRoom == null) {
 | 
				
			||||||
					throw new ApiError(meta.errors.noSuchGroup);
 | 
										throw new ApiError(meta.errors.noSuchRoom);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// check joined
 | 
									// check joined
 | 
				
			||||||
				const joining = await this.userGroupJoiningsRepository.findOneBy({
 | 
									const joining = await this.userRoomJoiningsRepository.findOneBy({
 | 
				
			||||||
					userId: me.id,
 | 
										userId: me.id,
 | 
				
			||||||
					userGroupId: recipientGroup.id,
 | 
										userRoomId: recipientRoom.id,
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (joining == null) {
 | 
									if (joining == null) {
 | 
				
			||||||
					throw new ApiError(meta.errors.groupAccessDenied);
 | 
										throw new ApiError(meta.errors.roomAccessDenied);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}*/
 | 
								}*/
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ export const paramDef = {
 | 
				
			|||||||
	type: 'object',
 | 
						type: 'object',
 | 
				
			||||||
	properties: {
 | 
						properties: {
 | 
				
			||||||
		limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
 | 
							limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
 | 
				
			||||||
		group: { type: 'boolean', default: false },
 | 
							room: { type: 'boolean', default: false },
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
} as const;
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,7 +46,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			|||||||
		private chatService: ChatService,
 | 
							private chatService: ChatService,
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		super(meta, paramDef, async (ps, me) => {
 | 
							super(meta, paramDef, async (ps, me) => {
 | 
				
			||||||
			const history = ps.group ? await this.chatService.groupHistory(me.id, ps.limit) : await this.chatService.userHistory(me.id, ps.limit);
 | 
								const history = ps.room ? await this.chatService.roomHistory(me.id, ps.limit) : await this.chatService.userHistory(me.id, ps.limit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return await this.chatMessageEntityService.packMany(history, me);
 | 
								return await this.chatMessageEntityService.packMany(history, me);
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,15 +35,15 @@ export const meta = {
 | 
				
			|||||||
			id: '11795c64-40ea-4198-b06e-3c873ed9039d',
 | 
								id: '11795c64-40ea-4198-b06e-3c873ed9039d',
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		noSuchGroup: {
 | 
							noSuchRoom: {
 | 
				
			||||||
			message: 'No such group.',
 | 
								message: 'No such room.',
 | 
				
			||||||
			code: 'NO_SUCH_GROUP',
 | 
								code: 'NO_SUCH_ROOM',
 | 
				
			||||||
			id: 'c4d9f88c-9270-4632-b032-6ed8cee36f7f',
 | 
								id: 'c4d9f88c-9270-4632-b032-6ed8cee36f7f',
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		groupAccessDenied: {
 | 
							roomAccessDenied: {
 | 
				
			||||||
			message: 'You can not read messages of groups that you have not joined.',
 | 
								message: 'You can not read messages of rooms that you have not joined.',
 | 
				
			||||||
			code: 'GROUP_ACCESS_DENIED',
 | 
								code: 'ROOM_ACCESS_DENIED',
 | 
				
			||||||
			id: 'a053a8dd-a491-4718-8f87-50775aad9284',
 | 
								id: 'a053a8dd-a491-4718-8f87-50775aad9284',
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -76,36 +76,36 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
				
			|||||||
				const messages = await this.chatService.userTimeline(me.id, other.id, ps.sinceId, ps.untilId, ps.limit);
 | 
									const messages = await this.chatService.userTimeline(me.id, other.id, ps.sinceId, ps.untilId, ps.limit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				return await this.chatMessageEntityService.packLiteMany(messages);
 | 
									return await this.chatMessageEntityService.packLiteMany(messages);
 | 
				
			||||||
			}/* else if (ps.groupId != null) {
 | 
								}/* else if (ps.roomId != null) {
 | 
				
			||||||
				// Fetch recipient (group)
 | 
									// Fetch recipient (room)
 | 
				
			||||||
				const recipientGroup = await this.userGroupRepository.findOneBy({ id: ps.groupId });
 | 
									const recipientRoom = await this.userRoomRepository.findOneBy({ id: ps.roomId });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (recipientGroup == null) {
 | 
									if (recipientRoom == null) {
 | 
				
			||||||
					throw new ApiError(meta.errors.noSuchGroup);
 | 
										throw new ApiError(meta.errors.noSuchRoom);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// check joined
 | 
									// check joined
 | 
				
			||||||
				const joining = await this.userGroupJoiningsRepository.findOneBy({
 | 
									const joining = await this.userRoomJoiningsRepository.findOneBy({
 | 
				
			||||||
					userId: me.id,
 | 
										userId: me.id,
 | 
				
			||||||
					userGroupId: recipientGroup.id,
 | 
										userRoomId: recipientRoom.id,
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (joining == null) {
 | 
									if (joining == null) {
 | 
				
			||||||
					throw new ApiError(meta.errors.groupAccessDenied);
 | 
										throw new ApiError(meta.errors.roomAccessDenied);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				const query = this.queryService.makePaginationQuery(this.messagingMessagesRepository.createQueryBuilder('message'), ps.sinceId, ps.untilId)
 | 
									const query = this.queryService.makePaginationQuery(this.messagingMessagesRepository.createQueryBuilder('message'), ps.sinceId, ps.untilId)
 | 
				
			||||||
					.andWhere('message.groupId = :groupId', { groupId: recipientGroup.id });
 | 
										.andWhere('message.roomId = :roomId', { roomId: recipientRoom.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				const messages = await query.take(ps.limit).getMany();
 | 
									const messages = await query.take(ps.limit).getMany();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Mark all as read
 | 
									// Mark all as read
 | 
				
			||||||
				if (ps.markAsRead) {
 | 
									if (ps.markAsRead) {
 | 
				
			||||||
					this.messagingService.readGroupMessagingMessage(me.id, recipientGroup.id, messages.map(x => x.id));
 | 
										this.messagingService.readRoomMessagingMessage(me.id, recipientRoom.id, messages.map(x => x.id));
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				return await Promise.all(messages.map(message => this.messagingMessageEntityService.pack(message, me, {
 | 
									return await Promise.all(messages.map(message => this.messagingMessageEntityService.pack(message, me, {
 | 
				
			||||||
					populateGroup: false,
 | 
										populateRoom: false,
 | 
				
			||||||
				})));
 | 
									})));
 | 
				
			||||||
			}*/
 | 
								}*/
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user