This commit is contained in:
syuilo
2025-03-23 16:51:35 +09:00
parent 9e23531adc
commit b98d3cbc29
25 changed files with 1836 additions and 5 deletions

View File

@@ -16,13 +16,15 @@ import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { PushNotificationService } from '@/core/PushNotificationService.js'; import { PushNotificationService } from '@/core/PushNotificationService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { ChatApprovalsRepository, ChatMessagesRepository, ChatRoomInvitationsRepository, ChatRoomMembershipsRepository, ChatRoomsRepository, MiChatMessage, MiChatRoom, MiDriveFile, MiUser, MutingsRepository, UsersRepository } from '@/models/_.js'; import type { ChatApprovalsRepository, ChatMessagesRepository, ChatRoomInvitationsRepository, ChatRoomMembershipsRepository, ChatRoomsRepository, MiChatMessage, MiChatRoom, MiChatRoomMembership, MiDriveFile, MiUser, MutingsRepository, UsersRepository } from '@/models/_.js';
import { UserBlockingService } from '@/core/UserBlockingService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js';
import { QueryService } from '@/core/QueryService.js'; import { QueryService } from '@/core/QueryService.js';
import { RoleService } from '@/core/RoleService.js'; import { RoleService } from '@/core/RoleService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js';
import { MiChatRoomInvitation } from '@/models/ChatRoomInvitation.js'; import { MiChatRoomInvitation } from '@/models/ChatRoomInvitation.js';
const MAX_ROOM_MEMBERS = 30;
@Injectable() @Injectable()
export class ChatService { export class ChatService {
constructor( constructor(
@@ -463,6 +465,22 @@ export class ChatService {
await this.chatRoomsRepository.delete(room.id); await this.chatRoomsRepository.delete(room.id);
} }
@bindThis
public async findMyRoomById(ownerId: MiUser['id'], roomId: MiChatRoom['id']) {
return this.chatRoomsRepository.findOneBy({ id: roomId, ownerId: ownerId });
}
@bindThis
public async findRoomById(roomId: MiChatRoom['id']) {
return this.chatRoomsRepository.findOneBy({ id: roomId });
}
@bindThis
public async isRoomMember(roomId: MiChatRoom['id'], userId: MiUser['id']) {
const membership = await this.chatRoomMembershipsRepository.findOneBy({ roomId, userId });
return membership != null;
}
@bindThis @bindThis
public async createRoomInvitation(inviterId: MiUser['id'], roomId: MiChatRoom['id'], inviteeId: MiUser['id']) { public async createRoomInvitation(inviterId: MiUser['id'], roomId: MiChatRoom['id'], inviteeId: MiUser['id']) {
if (inviterId === inviteeId) { if (inviterId === inviteeId) {
@@ -471,6 +489,16 @@ export class ChatService {
const room = await this.chatRoomsRepository.findOneByOrFail({ id: roomId, ownerId: inviterId }); const room = await this.chatRoomsRepository.findOneByOrFail({ id: roomId, ownerId: inviterId });
const existingInvitation = await this.chatRoomInvitationsRepository.findOneBy({ roomId, userId: inviteeId });
if (existingInvitation) {
throw new Error('already invited');
}
const membershipsCount = await this.chatRoomMembershipsRepository.countBy({ roomId });
if (membershipsCount >= MAX_ROOM_MEMBERS) {
throw new Error('room is full');
}
// TODO: cehck block // TODO: cehck block
const invitation = { const invitation = {
@@ -483,4 +511,80 @@ export class ChatService {
return created; return created;
} }
@bindThis
public async getOwnedRoomsWithPagination(ownerId: MiUser['id'], limit: number, sinceId?: MiChatRoom['id'] | null, untilId?: MiChatRoom['id'] | null) {
const query = this.queryService.makePaginationQuery(this.chatRoomsRepository.createQueryBuilder('room'), sinceId, untilId)
.where('room.ownerId = :ownerId', { ownerId });
const rooms = await query.take(limit).getMany();
return rooms;
}
@bindThis
public async getReceivedRoomInvitationsWithPagination(userId: MiUser['id'], limit: number, sinceId?: MiChatRoomInvitation['id'] | null, untilId?: MiChatRoomInvitation['id'] | null) {
const query = this.queryService.makePaginationQuery(this.chatRoomInvitationsRepository.createQueryBuilder('invitation'), sinceId, untilId)
.where('invitation.userId = :userId', { userId });
const invitations = await query.take(limit).getMany();
return invitations;
}
@bindThis
public async joinToRoom(userId: MiUser['id'], roomId: MiChatRoom['id']) {
const invitation = await this.chatRoomInvitationsRepository.findOneByOrFail({ roomId, userId });
const membershipsCount = await this.chatRoomMembershipsRepository.countBy({ roomId });
if (membershipsCount >= MAX_ROOM_MEMBERS) {
throw new Error('room is full');
}
const membership = {
id: this.idService.gen(),
roomId: roomId,
userId: userId,
} satisfies Partial<MiChatRoomMembership>;
// TODO: transaction
await this.chatRoomMembershipsRepository.insertOne(membership);
await this.chatRoomInvitationsRepository.delete(invitation.id);
}
@bindThis
public async rejectRoomInvitation(userId: MiUser['id'], roomId: MiChatRoom['id']) {
const invitation = await this.chatRoomInvitationsRepository.findOneByOrFail({ roomId, userId });
await this.chatRoomInvitationsRepository.delete(invitation.id);
}
@bindThis
public async leaveRoom(userId: MiUser['id'], roomId: MiChatRoom['id']) {
const membership = await this.chatRoomMembershipsRepository.findOneByOrFail({ roomId, userId });
await this.chatRoomMembershipsRepository.delete(membership.id);
}
@bindThis
public async updateRoom(room: MiChatRoom, params: {
name?: string;
}): Promise<MiChatRoom> {
return this.chatRoomsRepository.createQueryBuilder().update()
.set(params)
.where('id = :id', { id: room.id })
.returning('*')
.execute()
.then((response) => {
return response.raw[0];
});
}
@bindThis
public async getRoomMembershipsWithPagination(roomId: MiChatRoom['id'], limit: number, sinceId?: MiChatRoomMembership['id'] | null, untilId?: MiChatRoomMembership['id'] | null) {
const query = this.queryService.makePaginationQuery(this.chatRoomMembershipsRepository.createQueryBuilder('membership'), sinceId, untilId)
.where('membership.roomId = :roomId', { roomId });
const memberships = await query.take(limit).getMany();
return memberships;
}
} }

View File

@@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { MiUser, ChatMessagesRepository, MiChatMessage, ChatRoomsRepository, MiChatRoom } from '@/models/_.js'; import type { MiUser, ChatMessagesRepository, MiChatMessage, ChatRoomsRepository, MiChatRoom, MiChatRoomInvitation, ChatRoomInvitationsRepository, MiChatRoomMembership, ChatRoomMembershipsRepository } from '@/models/_.js';
import { awaitAll } from '@/misc/prelude/await-all.js'; import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js'; import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/Blocking.js'; import type { } from '@/models/Blocking.js';
@@ -23,6 +23,12 @@ export class ChatEntityService {
@Inject(DI.chatRoomsRepository) @Inject(DI.chatRoomsRepository)
private chatRoomsRepository: ChatRoomsRepository, private chatRoomsRepository: ChatRoomsRepository,
@Inject(DI.chatRoomInvitationsRepository)
private chatRoomInvitationsRepository: ChatRoomInvitationsRepository,
@Inject(DI.chatRoomMembershipsRepository)
private chatRoomMembershipsRepository: ChatRoomMembershipsRepository,
private userEntityService: UserEntityService, private userEntityService: UserEntityService,
private driveFileEntityService: DriveFileEntityService, private driveFileEntityService: DriveFileEntityService,
private idService: IdService, private idService: IdService,
@@ -206,4 +212,72 @@ export class ChatEntityService {
return Promise.all(rooms.map(room => this.packRoom(room, me, { _hint_: { packedOwners } }))); return Promise.all(rooms.map(room => this.packRoom(room, me, { _hint_: { packedOwners } })));
} }
@bindThis
public async packRoomInvitation(
src: MiChatRoomInvitation['id'] | MiChatRoomInvitation,
me: { id: MiUser['id'] },
options?: {
_hint_?: {
packedRooms: Map<MiChatRoomInvitation['roomId'], Packed<'ChatRoom'>>;
packedUsers: Map<MiChatRoomInvitation['id'], Packed<'UserLite'>>;
};
},
): Promise<Packed<'ChatRoomInvitation'>> {
const invitation = typeof src === 'object' ? src : await this.chatRoomInvitationsRepository.findOneByOrFail({ id: src });
return {
id: invitation.id,
createdAt: this.idService.parse(invitation.id).date.toISOString(),
roomId: invitation.roomId,
room: options?._hint_?.packedRooms.get(invitation.roomId) ?? await this.packRoom(invitation.room ?? invitation.roomId, me),
userId: invitation.userId,
user: options?._hint_?.packedUsers.get(invitation.userId) ?? await this.userEntityService.pack(invitation.user ?? invitation.userId, me),
};
}
@bindThis
public async packRoomInvitations(
invitations: MiChatRoomInvitation[],
me: { id: MiUser['id'] },
) {
if (invitations.length === 0) return [];
return Promise.all(invitations.map(invitation => this.packRoomInvitation(invitation, me)));
}
@bindThis
public async packRoomMembership(
src: MiChatRoomMembership['id'] | MiChatRoomMembership,
me: { id: MiUser['id'] },
options?: {
_hint_?: {
packedUsers: Map<MiChatRoomMembership['id'], Packed<'UserLite'>>;
};
},
): Promise<Packed<'ChatRoomMembership'>> {
const membership = typeof src === 'object' ? src : await this.chatRoomMembershipsRepository.findOneByOrFail({ id: src });
return {
id: membership.id,
createdAt: this.idService.parse(membership.id).date.toISOString(),
userId: membership.userId,
user: options?._hint_?.packedUsers.get(membership.userId) ?? await this.userEntityService.pack(membership.user ?? membership.userId, me),
};
}
@bindThis
public async packRoomMemberships(
memberships: MiChatRoomMembership[],
me: { id: MiUser['id'] },
) {
if (memberships.length === 0) return [];
const users = memberships.map(x => x.user ?? x.userId);
const packedUsers = await this.userEntityService.packMany(users, me)
.then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(memberships.map(membership => this.packRoomMembership(membership, me, { _hint_: { packedUsers } })));
}
} }

View File

@@ -65,6 +65,8 @@ import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.j
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js'; import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
import { packedChatMessageSchema, packedChatMessageLiteSchema } from '@/models/json-schema/chat-message.js'; import { packedChatMessageSchema, packedChatMessageLiteSchema } from '@/models/json-schema/chat-message.js';
import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js'; import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
export const refs = { export const refs = {
UserLite: packedUserLiteSchema, UserLite: packedUserLiteSchema,
@@ -125,6 +127,8 @@ export const refs = {
ChatMessage: packedChatMessageSchema, ChatMessage: packedChatMessageSchema,
ChatMessageLite: packedChatMessageLiteSchema, ChatMessageLite: packedChatMessageLiteSchema,
ChatRoom: packedChatRoomSchema, ChatRoom: packedChatRoomSchema,
ChatRoomInvitation: packedChatRoomInvitationSchema,
ChatRoomMembership: packedChatRoomMembershipSchema,
}; };
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>; export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;

View File

@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export const packedChatRoomInvitationSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
},
createdAt: {
type: 'string',
format: 'date-time',
optional: false, nullable: false,
},
userId: {
type: 'string',
optional: false, nullable: false,
},
user: {
type: 'object',
optional: false, nullable: false,
ref: 'UserLite',
},
roomId: {
type: 'string',
optional: false, nullable: false,
},
room: {
type: 'object',
optional: false, nullable: false,
ref: 'ChatRoom',
},
},
} as const;

View File

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

View File

@@ -400,5 +400,16 @@ export * as 'chat/messages/create' from './endpoints/chat/messages/create.js';
export * as 'chat/messages/delete' from './endpoints/chat/messages/delete.js'; export * as 'chat/messages/delete' from './endpoints/chat/messages/delete.js';
export * as 'chat/messages/show' from './endpoints/chat/messages/show.js'; export * as 'chat/messages/show' from './endpoints/chat/messages/show.js';
export * as 'chat/messages/timeline' from './endpoints/chat/messages/timeline.js'; export * as 'chat/messages/timeline' from './endpoints/chat/messages/timeline.js';
export * as 'chat/rooms/create' from './endpoints/chat/rooms/create.js';
export * as 'chat/rooms/delete' from './endpoints/chat/rooms/delete.js';
export * as 'chat/rooms/join' from './endpoints/chat/rooms/join.js';
export * as 'chat/rooms/leave' from './endpoints/chat/rooms/leave.js';
export * as 'chat/rooms/show' from './endpoints/chat/rooms/show.js';
export * as 'chat/rooms/owned' from './endpoints/chat/rooms/owned.js';
export * as 'chat/rooms/update' from './endpoints/chat/rooms/update.js';
export * as 'chat/rooms/members' from './endpoints/chat/rooms/members.js';
export * as 'chat/rooms/invitations/create' from './endpoints/chat/rooms/invitations/create.js';
export * as 'chat/rooms/invitations/reject' from './endpoints/chat/rooms/invitations/reject.js';
export * as 'chat/rooms/invitations/inbox' from './endpoints/chat/rooms/invitations/inbox.js';
export * as 'chat/history' from './endpoints/chat/history.js'; export * as 'chat/history' from './endpoints/chat/history.js';
export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js'; export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js';

View File

@@ -6,9 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js';
import { ChatService } from '@/core/ChatService.js'; import { ChatService } from '@/core/ChatService.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
import { ApiError } from '@/server/api/error.js'; import { ApiError } from '@/server/api/error.js';
export const meta = { export const meta = {

View File

@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'write:chat',
res: {
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: 'd4e3753d-97bf-4a19-ab8e-21080fbc0f4b',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
) {
super(meta, paramDef, async (ps, me) => {
const room = await this.chatService.findMyRoomById(me.id, ps.roomId);
if (room == null) {
throw new ApiError(meta.errors.noSuchRoom);
}
await this.chatService.deleteRoom(room);
});
}
}

View File

@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import ms from 'ms';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '@/server/api/error.js';
import { ChatService } from '@/core/ChatService.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
requiredRolePolicy: 'canChat',
prohibitMoved: true,
kind: 'write:chat',
limit: {
duration: ms('1day'),
max: 50,
},
res: {
type: 'object',
optional: false, nullable: false,
ref: 'ChatRoomInvitation',
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: '916f9507-49ba-4e90-b57f-1fd4deaa47a5',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
userId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId', 'userId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
private chatEntityService: ChatEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const room = await this.chatService.findMyRoomById(me.id, ps.roomId);
if (room == null) {
throw new ApiError(meta.errors.noSuchRoom);
}
const invitation = await this.chatService.createRoomInvitation(ps.userId, room.id, ps.userId);
return await this.chatEntityService.packRoomInvitation(invitation, me);
});
}
}

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'read:chat',
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'ChatRoomInvitation',
},
},
errors: {
},
} as const;
export const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatEntityService: ChatEntityService,
private chatService: ChatService,
) {
super(meta, paramDef, async (ps, me) => {
const invitations = await this.chatService.getReceivedRoomInvitationsWithPagination(me.id, ps.limit, ps.sinceId, ps.untilId);
return this.chatEntityService.packRoomInvitations(invitations, me);
});
}
}

View File

@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'write:chat',
res: {
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: '5130557e-5a11-4cfb-9cc5-fe60cda5de0d',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
) {
super(meta, paramDef, async (ps, me) => {
await this.chatService.rejectRoomInvitation(me.id, ps.roomId);
});
}
}

View File

@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'write:chat',
res: {
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: '84416476-5ce8-4a2c-b568-9569f1b10733',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
) {
super(meta, paramDef, async (ps, me) => {
await this.chatService.joinToRoom(me.id, ps.roomId);
});
}
}

View File

@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'write:chat',
res: {
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: 'cb7f3179-50e8-4389-8c30-dbe2650a67c9',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
) {
super(meta, paramDef, async (ps, me) => {
await this.chatService.leaveRoom(me.id, ps.roomId);
});
}
}

View File

@@ -0,0 +1,71 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ApiError } from '@/server/api/error.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'write:chat',
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'ChatRoomMembership',
},
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: '7b9fe84c-eafc-4d21-bf89-485458ed2c18',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
private chatEntityService: ChatEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const room = await this.chatService.findRoomById(ps.roomId);
if (room == null) {
throw new ApiError(meta.errors.noSuchRoom);
}
if (!(await this.chatService.isRoomMember(room.id, me.id)) && room.ownerId !== me.id) {
throw new ApiError(meta.errors.noSuchRoom);
}
const memberships = await this.chatService.getRoomMembershipsWithPagination(room.id, ps.limit, ps.sinceId, ps.untilId);
return this.chatEntityService.packRoomMemberships(memberships, me);
});
}
}

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'read:chat',
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'ChatRoom',
},
},
errors: {
},
} as const;
export const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatEntityService: ChatEntityService,
private chatService: ChatService,
) {
super(meta, paramDef, async (ps, me) => {
const rooms = await this.chatService.getOwnedRoomsWithPagination(me.id, ps.limit, ps.sinceId, ps.untilId);
return this.chatEntityService.packRooms(rooms, me);
});
}
}

View File

@@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ApiError } from '@/server/api/error.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'read:chat',
res: {
type: 'object',
optional: false, nullable: false,
ref: 'ChatRoom',
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: '857ae02f-8759-4d20-9adb-6e95fffe4fd7',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
private chatEntityService: ChatEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const room = await this.chatService.findRoomById(ps.roomId);
if (room == null) {
throw new ApiError(meta.errors.noSuchRoom);
}
return this.chatEntityService.packRoom(room, me);
});
}
}

View File

@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ApiError } from '@/server/api/error.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
export const meta = {
tags: ['chat'],
requireCredential: true,
kind: 'write:chat',
res: {
type: 'object',
optional: false, nullable: false,
ref: 'ChatRoom',
},
errors: {
noSuchRoom: {
message: 'No such room.',
code: 'NO_SUCH_ROOM',
id: 'fcdb0f92-bda6-47f9-bd05-343e0e020932',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
roomId: { type: 'string', format: 'misskey:id' },
name: { type: 'string', maxLength: 256 },
},
required: ['roomId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private chatService: ChatService,
private chatEntityService: ChatEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const room = await this.chatService.findMyRoomById(me.id, ps.roomId);
if (room == null) {
throw new ApiError(meta.errors.noSuchRoom);
}
const updated = await this.chatService.updateRoom(room, {
name: ps.name,
});
return this.chatEntityService.packRoom(updated, me);
});
}
}

View File

@@ -986,6 +986,78 @@ type ChatMessagesTimelineResponse = operations['chat___messages___timeline']['re
// @public (undocumented) // @public (undocumented)
type ChatRoom = components['schemas']['ChatRoom']; type ChatRoom = components['schemas']['ChatRoom'];
// @public (undocumented)
type ChatRoomInvitation = components['schemas']['ChatRoomInvitation'];
// @public (undocumented)
type ChatRoomMembership = components['schemas']['ChatRoomMembership'];
// @public (undocumented)
type ChatRoomsCreateRequest = operations['chat___rooms___create']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsCreateResponse = operations['chat___rooms___create']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsDeleteRequest = operations['chat___rooms___delete']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsDeleteResponse = operations['chat___rooms___delete']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsInvitationsCreateRequest = operations['chat___rooms___invitations___create']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsInvitationsCreateResponse = operations['chat___rooms___invitations___create']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsInvitationsInboxRequest = operations['chat___rooms___invitations___inbox']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsInvitationsInboxResponse = operations['chat___rooms___invitations___inbox']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsInvitationsRejectRequest = operations['chat___rooms___invitations___reject']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsInvitationsRejectResponse = operations['chat___rooms___invitations___reject']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsJoinRequest = operations['chat___rooms___join']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsJoinResponse = operations['chat___rooms___join']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsLeaveRequest = operations['chat___rooms___leave']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsLeaveResponse = operations['chat___rooms___leave']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsMembersRequest = operations['chat___rooms___members']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsMembersResponse = operations['chat___rooms___members']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsOwnedRequest = operations['chat___rooms___owned']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsOwnedResponse = operations['chat___rooms___owned']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsShowRequest = operations['chat___rooms___show']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsShowResponse = operations['chat___rooms___show']['responses']['200']['content']['application/json'];
// @public (undocumented)
type ChatRoomsUpdateRequest = operations['chat___rooms___update']['requestBody']['content']['application/json'];
// @public (undocumented)
type ChatRoomsUpdateResponse = operations['chat___rooms___update']['responses']['200']['content']['application/json'];
// @public (undocumented) // @public (undocumented)
type Clip = components['schemas']['Clip']; type Clip = components['schemas']['Clip'];
@@ -1493,6 +1565,28 @@ declare namespace entities {
ChatMessagesShowResponse, ChatMessagesShowResponse,
ChatMessagesTimelineRequest, ChatMessagesTimelineRequest,
ChatMessagesTimelineResponse, ChatMessagesTimelineResponse,
ChatRoomsCreateRequest,
ChatRoomsCreateResponse,
ChatRoomsDeleteRequest,
ChatRoomsDeleteResponse,
ChatRoomsInvitationsCreateRequest,
ChatRoomsInvitationsCreateResponse,
ChatRoomsInvitationsInboxRequest,
ChatRoomsInvitationsInboxResponse,
ChatRoomsInvitationsRejectRequest,
ChatRoomsInvitationsRejectResponse,
ChatRoomsJoinRequest,
ChatRoomsJoinResponse,
ChatRoomsLeaveRequest,
ChatRoomsLeaveResponse,
ChatRoomsMembersRequest,
ChatRoomsMembersResponse,
ChatRoomsOwnedRequest,
ChatRoomsOwnedResponse,
ChatRoomsShowRequest,
ChatRoomsShowResponse,
ChatRoomsUpdateRequest,
ChatRoomsUpdateResponse,
ClipsAddNoteRequest, ClipsAddNoteRequest,
ClipsCreateRequest, ClipsCreateRequest,
ClipsCreateResponse, ClipsCreateResponse,
@@ -1928,7 +2022,9 @@ declare namespace entities {
AbuseReportNotificationRecipient, AbuseReportNotificationRecipient,
ChatMessage, ChatMessage,
ChatMessageLite, ChatMessageLite,
ChatRoom ChatRoom,
ChatRoomInvitation,
ChatRoomMembership
} }
} }
export { entities } export { entities }

View File

@@ -1589,6 +1589,127 @@ declare module '../api.js' {
credential?: string | null, credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>; ): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/create', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/delete', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/invitations/create', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
request<E extends 'chat/rooms/invitations/inbox', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/invitations/reject', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/join', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/leave', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/members', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
request<E extends 'chat/rooms/owned', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
request<E extends 'chat/rooms/show', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
request<E extends 'chat/rooms/update', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/** /**
* No description provided. * No description provided.
* *

View File

@@ -217,6 +217,28 @@ import type {
ChatMessagesShowResponse, ChatMessagesShowResponse,
ChatMessagesTimelineRequest, ChatMessagesTimelineRequest,
ChatMessagesTimelineResponse, ChatMessagesTimelineResponse,
ChatRoomsCreateRequest,
ChatRoomsCreateResponse,
ChatRoomsDeleteRequest,
ChatRoomsDeleteResponse,
ChatRoomsInvitationsCreateRequest,
ChatRoomsInvitationsCreateResponse,
ChatRoomsInvitationsInboxRequest,
ChatRoomsInvitationsInboxResponse,
ChatRoomsInvitationsRejectRequest,
ChatRoomsInvitationsRejectResponse,
ChatRoomsJoinRequest,
ChatRoomsJoinResponse,
ChatRoomsLeaveRequest,
ChatRoomsLeaveResponse,
ChatRoomsMembersRequest,
ChatRoomsMembersResponse,
ChatRoomsOwnedRequest,
ChatRoomsOwnedResponse,
ChatRoomsShowRequest,
ChatRoomsShowResponse,
ChatRoomsUpdateRequest,
ChatRoomsUpdateResponse,
ClipsAddNoteRequest, ClipsAddNoteRequest,
ClipsCreateRequest, ClipsCreateRequest,
ClipsCreateResponse, ClipsCreateResponse,
@@ -741,6 +763,17 @@ export type Endpoints = {
'chat/messages/delete': { req: ChatMessagesDeleteRequest; res: ChatMessagesDeleteResponse }; 'chat/messages/delete': { req: ChatMessagesDeleteRequest; res: ChatMessagesDeleteResponse };
'chat/messages/show': { req: ChatMessagesShowRequest; res: ChatMessagesShowResponse }; 'chat/messages/show': { req: ChatMessagesShowRequest; res: ChatMessagesShowResponse };
'chat/messages/timeline': { req: ChatMessagesTimelineRequest; res: ChatMessagesTimelineResponse }; 'chat/messages/timeline': { req: ChatMessagesTimelineRequest; res: ChatMessagesTimelineResponse };
'chat/rooms/create': { req: ChatRoomsCreateRequest; res: ChatRoomsCreateResponse };
'chat/rooms/delete': { req: ChatRoomsDeleteRequest; res: ChatRoomsDeleteResponse };
'chat/rooms/invitations/create': { req: ChatRoomsInvitationsCreateRequest; res: ChatRoomsInvitationsCreateResponse };
'chat/rooms/invitations/inbox': { req: ChatRoomsInvitationsInboxRequest; res: ChatRoomsInvitationsInboxResponse };
'chat/rooms/invitations/reject': { req: ChatRoomsInvitationsRejectRequest; res: ChatRoomsInvitationsRejectResponse };
'chat/rooms/join': { req: ChatRoomsJoinRequest; res: ChatRoomsJoinResponse };
'chat/rooms/leave': { req: ChatRoomsLeaveRequest; res: ChatRoomsLeaveResponse };
'chat/rooms/members': { req: ChatRoomsMembersRequest; res: ChatRoomsMembersResponse };
'chat/rooms/owned': { req: ChatRoomsOwnedRequest; res: ChatRoomsOwnedResponse };
'chat/rooms/show': { req: ChatRoomsShowRequest; res: ChatRoomsShowResponse };
'chat/rooms/update': { req: ChatRoomsUpdateRequest; res: ChatRoomsUpdateResponse };
'clips/add-note': { req: ClipsAddNoteRequest; res: EmptyResponse }; 'clips/add-note': { req: ClipsAddNoteRequest; res: EmptyResponse };
'clips/create': { req: ClipsCreateRequest; res: ClipsCreateResponse }; 'clips/create': { req: ClipsCreateRequest; res: ClipsCreateResponse };
'clips/delete': { req: ClipsDeleteRequest; res: EmptyResponse }; 'clips/delete': { req: ClipsDeleteRequest; res: EmptyResponse };

View File

@@ -220,6 +220,28 @@ export type ChatMessagesShowRequest = operations['chat___messages___show']['requ
export type ChatMessagesShowResponse = operations['chat___messages___show']['responses']['200']['content']['application/json']; export type ChatMessagesShowResponse = operations['chat___messages___show']['responses']['200']['content']['application/json'];
export type ChatMessagesTimelineRequest = operations['chat___messages___timeline']['requestBody']['content']['application/json']; export type ChatMessagesTimelineRequest = operations['chat___messages___timeline']['requestBody']['content']['application/json'];
export type ChatMessagesTimelineResponse = operations['chat___messages___timeline']['responses']['200']['content']['application/json']; export type ChatMessagesTimelineResponse = operations['chat___messages___timeline']['responses']['200']['content']['application/json'];
export type ChatRoomsCreateRequest = operations['chat___rooms___create']['requestBody']['content']['application/json'];
export type ChatRoomsCreateResponse = operations['chat___rooms___create']['responses']['200']['content']['application/json'];
export type ChatRoomsDeleteRequest = operations['chat___rooms___delete']['requestBody']['content']['application/json'];
export type ChatRoomsDeleteResponse = operations['chat___rooms___delete']['responses']['200']['content']['application/json'];
export type ChatRoomsInvitationsCreateRequest = operations['chat___rooms___invitations___create']['requestBody']['content']['application/json'];
export type ChatRoomsInvitationsCreateResponse = operations['chat___rooms___invitations___create']['responses']['200']['content']['application/json'];
export type ChatRoomsInvitationsInboxRequest = operations['chat___rooms___invitations___inbox']['requestBody']['content']['application/json'];
export type ChatRoomsInvitationsInboxResponse = operations['chat___rooms___invitations___inbox']['responses']['200']['content']['application/json'];
export type ChatRoomsInvitationsRejectRequest = operations['chat___rooms___invitations___reject']['requestBody']['content']['application/json'];
export type ChatRoomsInvitationsRejectResponse = operations['chat___rooms___invitations___reject']['responses']['200']['content']['application/json'];
export type ChatRoomsJoinRequest = operations['chat___rooms___join']['requestBody']['content']['application/json'];
export type ChatRoomsJoinResponse = operations['chat___rooms___join']['responses']['200']['content']['application/json'];
export type ChatRoomsLeaveRequest = operations['chat___rooms___leave']['requestBody']['content']['application/json'];
export type ChatRoomsLeaveResponse = operations['chat___rooms___leave']['responses']['200']['content']['application/json'];
export type ChatRoomsMembersRequest = operations['chat___rooms___members']['requestBody']['content']['application/json'];
export type ChatRoomsMembersResponse = operations['chat___rooms___members']['responses']['200']['content']['application/json'];
export type ChatRoomsOwnedRequest = operations['chat___rooms___owned']['requestBody']['content']['application/json'];
export type ChatRoomsOwnedResponse = operations['chat___rooms___owned']['responses']['200']['content']['application/json'];
export type ChatRoomsShowRequest = operations['chat___rooms___show']['requestBody']['content']['application/json'];
export type ChatRoomsShowResponse = operations['chat___rooms___show']['responses']['200']['content']['application/json'];
export type ChatRoomsUpdateRequest = operations['chat___rooms___update']['requestBody']['content']['application/json'];
export type ChatRoomsUpdateResponse = operations['chat___rooms___update']['responses']['200']['content']['application/json'];
export type ClipsAddNoteRequest = operations['clips___add-note']['requestBody']['content']['application/json']; export type ClipsAddNoteRequest = operations['clips___add-note']['requestBody']['content']['application/json'];
export type ClipsCreateRequest = operations['clips___create']['requestBody']['content']['application/json']; export type ClipsCreateRequest = operations['clips___create']['requestBody']['content']['application/json'];
export type ClipsCreateResponse = operations['clips___create']['responses']['200']['content']['application/json']; export type ClipsCreateResponse = operations['clips___create']['responses']['200']['content']['application/json'];

View File

@@ -57,3 +57,5 @@ export type AbuseReportNotificationRecipient = components['schemas']['AbuseRepor
export type ChatMessage = components['schemas']['ChatMessage']; export type ChatMessage = components['schemas']['ChatMessage'];
export type ChatMessageLite = components['schemas']['ChatMessageLite']; export type ChatMessageLite = components['schemas']['ChatMessageLite'];
export type ChatRoom = components['schemas']['ChatRoom']; export type ChatRoom = components['schemas']['ChatRoom'];
export type ChatRoomInvitation = components['schemas']['ChatRoomInvitation'];
export type ChatRoomMembership = components['schemas']['ChatRoomMembership'];

View File

@@ -1403,6 +1403,105 @@ export type paths = {
*/ */
post: operations['chat___messages___timeline']; post: operations['chat___messages___timeline'];
}; };
'/chat/rooms/create': {
/**
* chat/rooms/create
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___create'];
};
'/chat/rooms/delete': {
/**
* chat/rooms/delete
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___delete'];
};
'/chat/rooms/invitations/create': {
/**
* chat/rooms/invitations/create
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___invitations___create'];
};
'/chat/rooms/invitations/inbox': {
/**
* chat/rooms/invitations/inbox
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
post: operations['chat___rooms___invitations___inbox'];
};
'/chat/rooms/invitations/reject': {
/**
* chat/rooms/invitations/reject
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___invitations___reject'];
};
'/chat/rooms/join': {
/**
* chat/rooms/join
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___join'];
};
'/chat/rooms/leave': {
/**
* chat/rooms/leave
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___leave'];
};
'/chat/rooms/members': {
/**
* chat/rooms/members
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___members'];
};
'/chat/rooms/owned': {
/**
* chat/rooms/owned
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
post: operations['chat___rooms___owned'];
};
'/chat/rooms/show': {
/**
* chat/rooms/show
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
post: operations['chat___rooms___show'];
};
'/chat/rooms/update': {
/**
* chat/rooms/update
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
post: operations['chat___rooms___update'];
};
'/clips/add-note': { '/clips/add-note': {
/** /**
* clips/add-note * clips/add-note
@@ -5220,6 +5319,22 @@ export type components = {
owner: components['schemas']['UserLite']; owner: components['schemas']['UserLite'];
name: string; name: string;
}; };
ChatRoomInvitation: {
id: string;
/** Format: date-time */
createdAt: string;
userId: string;
user: components['schemas']['UserLite'];
roomId: string;
room: components['schemas']['ChatRoom'];
};
ChatRoomMembership: {
id: string;
/** Format: date-time */
createdAt: string;
userId: string;
user: components['schemas']['UserLite'];
};
}; };
responses: never; responses: never;
parameters: never; parameters: never;
@@ -14030,6 +14145,628 @@ export type operations = {
}; };
}; };
}; };
/**
* chat/rooms/create
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___create: {
requestBody: {
content: {
'application/json': {
name: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': components['schemas']['ChatRoom'];
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Too many requests */
429: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/delete
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___delete: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': unknown;
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/invitations/create
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___invitations___create: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
/** Format: misskey:id */
userId: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': components['schemas']['ChatRoomInvitation'];
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Too many requests */
429: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/invitations/inbox
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
chat___rooms___invitations___inbox: {
requestBody: {
content: {
'application/json': {
/** @default 30 */
limit?: number;
/** Format: misskey:id */
sinceId?: string;
/** Format: misskey:id */
untilId?: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': components['schemas']['ChatRoomInvitation'][];
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/invitations/reject
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___invitations___reject: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': unknown;
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/join
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___join: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': unknown;
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/leave
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___leave: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': unknown;
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/members
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___members: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
/** @default 30 */
limit?: number;
/** Format: misskey:id */
sinceId?: string;
/** Format: misskey:id */
untilId?: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': components['schemas']['ChatRoomMembership'][];
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/owned
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
chat___rooms___owned: {
requestBody: {
content: {
'application/json': {
/** @default 30 */
limit?: number;
/** Format: misskey:id */
sinceId?: string;
/** Format: misskey:id */
untilId?: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': components['schemas']['ChatRoom'][];
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/show
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:chat*
*/
chat___rooms___show: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': components['schemas']['ChatRoom'];
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/**
* chat/rooms/update
* @description No description provided.
*
* **Credential required**: *Yes* / **Permission**: *write:chat*
*/
chat___rooms___update: {
requestBody: {
content: {
'application/json': {
/** Format: misskey:id */
roomId: string;
name?: string;
};
};
};
responses: {
/** @description OK (with results) */
200: {
content: {
'application/json': components['schemas']['ChatRoom'];
};
};
/** @description Client error */
400: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Authentication error */
401: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Forbidden error */
403: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description I'm Ai */
418: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** @description Internal server error */
500: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
};
/** /**
* clips/add-note * clips/add-note
* @description No description provided. * @description No description provided.