This commit is contained in:
syuilo
2025-03-18 10:27:30 +09:00
parent 86f2ababd1
commit 6b5cf2e229
31 changed files with 1136 additions and 159 deletions

View File

@@ -186,8 +186,8 @@ export class ChatService {
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);
}
}/* else if (message.roomId) {
this.globalEventService.publishRoomChatStream(message.roomId, 'deleted', message.id);
}/* else if (message.toRoomId) {
this.globalEventService.publishRoomChatStream(message.toRoomId, 'deleted', message.id);
}*/
}
@@ -245,7 +245,7 @@ export class ChatService {
} else {
// そのグループにおいて未読がなければイベント発行
const unreadExist = await this.chatMessagesRepository.createQueryBuilder('message')
.where('message.roomId = :roomId', { roomId: roomId })
.where('message.toRoomId = :roomId', { roomId: roomId })
.andWhere('message.userId != :userId', { userId: userId })
.andWhere('NOT (:userId = ANY(message.reads))', { userId: userId })
.andWhere('message.createdAt > :joinedAt', { joinedAt: joining.createdAt }) // 自分が加入する前の会話については、未読扱いしない
@@ -300,7 +300,7 @@ export class ChatService {
.where('message.fromUserId = :meId', { meId: meId })
.orWhere('message.toUserId = :meId', { meId: meId });
}))
.andWhere('message.roomId IS NULL')
.andWhere('message.toRoomId IS NULL')
.andWhere(`message.fromUserId NOT IN (${ mutingQuery.getQuery() })`)
.andWhere(`message.toUserId NOT IN (${ mutingQuery.getQuery() })`);
@@ -325,6 +325,7 @@ export class ChatService {
@bindThis
public async roomHistory(meId: MiUser['id'], limit: number): Promise<MiChatMessage[]> {
return [];
/*
const rooms = await this.userRoomJoiningsRepository.findBy({
userId: meId,
@@ -341,10 +342,10 @@ export class ChatService {
const query = this.chatMessagesRepository.createQueryBuilder('message')
.orderBy('message.id', 'DESC')
.where('message.roomId IN (:...rooms)', { rooms: rooms });
.where('message.toRoomId IN (:...rooms)', { rooms: rooms });
if (found.length > 0) {
query.andWhere('message.roomId NOT IN (:...found)', { found: found });
query.andWhere('message.toRoomId NOT IN (:...found)', { found: found });
}
const message = await query.getOne();

View File

@@ -84,6 +84,8 @@ export const DI = {
flashLikesRepository: Symbol('flashLikesRepository'),
userMemosRepository: Symbol('userMemosRepository'),
chatMessagesRepository: Symbol('chatMessagesRepository'),
chatRoomsRepository: Symbol('chatRoomsRepository'),
chatRoomMembershipsRepository: Symbol('chatRoomMembershipsRepository'),
bubbleGameRecordsRepository: Symbol('bubbleGameRecordsRepository'),
reversiGamesRepository: Symbol('reversiGamesRepository'),
//#endregion

View File

@@ -64,6 +64,7 @@ import {
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
import { packedChatMessageSchema, packedChatMessageLiteSchema } from '@/models/json-schema/chat-message.js';
import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
export const refs = {
UserLite: packedUserLiteSchema,
@@ -123,6 +124,7 @@ export const refs = {
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
ChatMessage: packedChatMessageSchema,
ChatMessageLite: packedChatMessageLiteSchema,
ChatRoom: packedChatRoomSchema,
};
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;

View File

@@ -9,6 +9,7 @@ import { MiUser } from './User.js';
import { MiChatRoom } from './ChatRoom.js';
@Entity('chat_room_membership')
@Index(['userId', 'roomId'], { unique: true })
export class MiChatRoomMembership {
@PrimaryColumn(id())
public id: string;

View File

@@ -78,6 +78,9 @@ import {
MiUserPublickey,
MiUserSecurityKey,
MiWebhook,
MiChatMessage,
MiChatRoom,
MiChatRoomMembership,
} from './_.js';
import type { Provider } from '@nestjs/common';
import type { DataSource } from 'typeorm';
@@ -490,6 +493,24 @@ const $userMemosRepository: Provider = {
inject: [DI.db],
};
const $chatMessagesRepository: Provider = {
provide: DI.chatMessagesRepository,
useFactory: (db: DataSource) => db.getRepository(MiChatMessage).extend(miRepository as MiRepository<MiChatMessage>),
inject: [DI.db],
};
const $chatRoomsRepository: Provider = {
provide: DI.chatRoomsRepository,
useFactory: (db: DataSource) => db.getRepository(MiChatRoom).extend(miRepository as MiRepository<MiChatRoom>),
inject: [DI.db],
};
const $chatRoomMembershipsRepository: Provider = {
provide: DI.chatRoomMembershipsRepository,
useFactory: (db: DataSource) => db.getRepository(MiChatRoomMembership).extend(miRepository as MiRepository<MiChatRoomMembership>),
inject: [DI.db],
};
const $bubbleGameRecordsRepository: Provider = {
provide: DI.bubbleGameRecordsRepository,
useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository<MiBubbleGameRecord>),
@@ -573,6 +594,9 @@ const $reversiGamesRepository: Provider = {
$flashsRepository,
$flashLikesRepository,
$userMemosRepository,
$chatMessagesRepository,
$chatRoomsRepository,
$chatRoomMembershipsRepository,
$bubbleGameRecordsRepository,
$reversiGamesRepository,
],
@@ -645,6 +669,9 @@ const $reversiGamesRepository: Provider = {
$flashsRepository,
$flashLikesRepository,
$userMemosRepository,
$chatMessagesRepository,
$chatRoomsRepository,
$chatRoomMembershipsRepository,
$bubbleGameRecordsRepository,
$reversiGamesRepository,
],

View File

@@ -21,7 +21,7 @@ export const packedChatMessageSchema = {
},
fromUser: {
type: 'object',
optional: true, nullable: false,
optional: false, nullable: false,
ref: 'UserLite',
},
toUserId: {
@@ -33,6 +33,15 @@ export const packedChatMessageSchema = {
optional: true, nullable: true,
ref: 'UserLite',
},
toRoomId: {
type: 'string',
optional: true, nullable: true,
},
toRoom: {
type: 'object',
optional: true, nullable: true,
ref: 'ChatRoom',
},
text: {
type: 'string',
optional: true, nullable: true,
@@ -73,6 +82,10 @@ export const packedChatMessageLiteSchema = {
type: 'string',
optional: true, nullable: true,
},
toRoomId: {
type: 'string',
optional: true, nullable: true,
},
text: {
type: 'string',
optional: true, nullable: true,

View File

@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export const packedChatRoomSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
},
createdAt: {
type: 'string',
format: 'date-time',
optional: false, nullable: false,
},
ownerId: {
type: 'string',
optional: false, nullable: false,
},
owner: {
type: 'object',
optional: false, nullable: false,
ref: 'UserLite',
},
name: {
type: 'string',
optional: false, nullable: false,
},
},
} as const;

View File

@@ -44,6 +44,7 @@ import { QueueStatsChannelService } from './api/stream/channels/queue-stats.js';
import { ServerStatsChannelService } from './api/stream/channels/server-stats.js';
import { UserListChannelService } from './api/stream/channels/user-list.js';
import { RoleTimelineChannelService } from './api/stream/channels/role-timeline.js';
import { ChatChannelService } from './api/stream/channels/chat.js';
import { ReversiChannelService } from './api/stream/channels/reversi.js';
import { ReversiGameChannelService } from './api/stream/channels/reversi-game.js';
import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.js';
@@ -84,6 +85,7 @@ import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.j
GlobalTimelineChannelService,
HashtagChannelService,
RoleTimelineChannelService,
ChatChannelService,
ReversiChannelService,
ReversiGameChannelService,
HomeTimelineChannelService,

View File

@@ -399,5 +399,5 @@ export * as 'users/show' from './endpoints/users/show.js';
export * as 'users/update-memo' from './endpoints/users/update-memo.js';
export * as 'chat/messages/create' from './endpoints/chat/messages/create.js';
export * as 'chat/messages/timeline' from './endpoints/chat/messages/timeline.js';
export * as 'chat/messages/history' from './endpoints/chat/messages/history.js';
export * as 'chat/history' from './endpoints/chat/history.js';
export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js';

View File

@@ -82,7 +82,7 @@ export const paramDef = {
properties: {
text: { type: 'string', nullable: true, maxLength: 2000 },
fileId: { type: 'string', format: 'misskey:id' },
userId: { type: 'string', format: 'misskey:id', nullable: true },
toUserId: { type: 'string', format: 'misskey:id', nullable: true },
},
} as const;
@@ -113,13 +113,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.contentRequired);
}
if (ps.userId != null) {
if (ps.toUserId != null) {
// Myself
if (ps.userId === me.id) {
if (ps.toUserId === me.id) {
throw new ApiError(meta.errors.recipientIsYourself);
}
const toUser = await this.getterService.getUser(ps.userId).catch(err => {
const toUser = await this.getterService.getUser(ps.toUserId).catch(err => {
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);
throw err;
});
@@ -130,9 +130,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
text: ps.text,
file: file,
});
}/* else if (ps.roomId != null) {
}/* else if (ps.toRoomId != null) {
// Fetch recipient (room)
recipientRoom = await this.userRoomsRepository.findOneBy({ id: ps.roomId! });
recipientRoom = await this.userRoomsRepository.findOneBy({ id: ps.toRoomId! });
if (recipientRoom == null) {
throw new ApiError(meta.errors.noSuchRoom);

View File

@@ -94,17 +94,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
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.chatMessagesRepository.createQueryBuilder('message'), ps.sinceId, ps.untilId)
.andWhere('message.roomId = :roomId', { roomId: recipientRoom.id });
const messages = await query.take(ps.limit).getMany();
// Mark all as read
if (ps.markAsRead) {
this.messagingService.readRoomMessagingMessage(me.id, recipientRoom.id, messages.map(x => x.id));
this.chatService.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.chatMessageEntityService.pack(message, me, {
populateRoom: false,
})));
}*/