mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-07-29 13:54:37 +02:00
wip
This commit is contained in:
30
packages/backend/migration/1779921322355-world-avatar.js
Normal file
30
packages/backend/migration/1779921322355-world-avatar.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class WorldAvatar1779921322355 {
|
||||
name = 'WorldAvatar1779921322355'
|
||||
|
||||
/**
|
||||
* @param {QueryRunner} queryRunner
|
||||
*/
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`CREATE TABLE "world_avatar" ("id" character varying(32) NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(256) NOT NULL, "userId" character varying(32) NOT NULL, "def" jsonb NOT NULL DEFAULT '{}', "active" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_e7a27262285cc2c27114871f866" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0f1d0bdfaca455cc2f13defabe" ON "world_avatar" ("updatedAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_4eba43c8e2540a92e99dd7f5a9" ON "world_avatar" ("userId") `);
|
||||
await queryRunner.query(`ALTER TABLE "world_room" ADD "accessCount" integer NOT NULL DEFAULT '0'`);
|
||||
await queryRunner.query(`ALTER TABLE "world_avatar" ADD CONSTRAINT "FK_4eba43c8e2540a92e99dd7f5a9a" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {QueryRunner} queryRunner
|
||||
*/
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "world_avatar" DROP CONSTRAINT "FK_4eba43c8e2540a92e99dd7f5a9a"`);
|
||||
await queryRunner.query(`ALTER TABLE "world_room" DROP COLUMN "accessCount"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_4eba43c8e2540a92e99dd7f5a9"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_0f1d0bdfaca455cc2f13defabe"`);
|
||||
await queryRunner.query(`DROP TABLE "world_avatar"`);
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,8 @@ import { LoggerService } from './LoggerService.js';
|
||||
import { WorldRoomService } from './WorldRoomService.js';
|
||||
import { WorldRoomEntityService } from './entities/WorldRoomEntityService.js';
|
||||
import { WorldRoomMultiplayService } from './WorldRoomMultiplayService.js';
|
||||
import { WorldAvatarService } from './WorldAvatarService.js';
|
||||
import { WorldAvatarEntityService } from './entities/WorldAvatarEntityService.js';
|
||||
import type { Provider } from '@nestjs/common';
|
||||
|
||||
//#region 文字列ベースでのinjection用(循環参照対応のため)
|
||||
@@ -234,6 +236,7 @@ const $ReversiService: Provider = { provide: 'ReversiService', useExisting: Reve
|
||||
const $PageService: Provider = { provide: 'PageService', useExisting: PageService };
|
||||
const $WorldRoomService: Provider = { provide: 'WorldRoomService', useExisting: WorldRoomService };
|
||||
const $WorldRoomMultiplayService: Provider = { provide: 'WorldRoomMultiplayService', useExisting: WorldRoomMultiplayService };
|
||||
const $WorldAvatarService: Provider = { provide: 'WorldAvatarService', useExisting: WorldAvatarService };
|
||||
|
||||
const $ChartLoggerService: Provider = { provide: 'ChartLoggerService', useExisting: ChartLoggerService };
|
||||
const $FederationChart: Provider = { provide: 'FederationChart', useExisting: FederationChart };
|
||||
@@ -290,6 +293,7 @@ const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService
|
||||
const $MetaEntityService: Provider = { provide: 'MetaEntityService', useExisting: MetaEntityService };
|
||||
const $SystemWebhookEntityService: Provider = { provide: 'SystemWebhookEntityService', useExisting: SystemWebhookEntityService };
|
||||
const $WorldRoomEntityService: Provider = { provide: 'WorldRoomEntityService', useExisting: WorldRoomEntityService };
|
||||
const $WorldAvatarEntityService: Provider = { provide: 'WorldAvatarEntityService', useExisting: WorldAvatarEntityService };
|
||||
|
||||
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
|
||||
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
|
||||
@@ -390,6 +394,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
PageService,
|
||||
WorldRoomService,
|
||||
WorldRoomMultiplayService,
|
||||
WorldAvatarService,
|
||||
|
||||
ChartLoggerService,
|
||||
FederationChart,
|
||||
@@ -446,6 +451,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
MetaEntityService,
|
||||
SystemWebhookEntityService,
|
||||
WorldRoomEntityService,
|
||||
WorldAvatarEntityService,
|
||||
|
||||
ApAudienceService,
|
||||
ApDbResolverService,
|
||||
@@ -543,6 +549,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$PageService,
|
||||
$WorldRoomService,
|
||||
$WorldRoomMultiplayService,
|
||||
$WorldAvatarService,
|
||||
|
||||
$ChartLoggerService,
|
||||
$FederationChart,
|
||||
@@ -599,6 +606,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$MetaEntityService,
|
||||
$SystemWebhookEntityService,
|
||||
$WorldRoomEntityService,
|
||||
$WorldAvatarEntityService,
|
||||
|
||||
$ApAudienceService,
|
||||
$ApDbResolverService,
|
||||
@@ -696,6 +704,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
PageService,
|
||||
WorldRoomService,
|
||||
WorldRoomMultiplayService,
|
||||
WorldAvatarService,
|
||||
|
||||
FederationChart,
|
||||
NotesChart,
|
||||
@@ -751,6 +760,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
MetaEntityService,
|
||||
SystemWebhookEntityService,
|
||||
WorldRoomEntityService,
|
||||
WorldAvatarEntityService,
|
||||
|
||||
ApAudienceService,
|
||||
ApDbResolverService,
|
||||
@@ -847,6 +857,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$PageService,
|
||||
$WorldRoomService,
|
||||
$WorldRoomMultiplayService,
|
||||
$WorldAvatarService,
|
||||
|
||||
$FederationChart,
|
||||
$NotesChart,
|
||||
@@ -902,6 +913,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$MetaEntityService,
|
||||
$SystemWebhookEntityService,
|
||||
$WorldRoomEntityService,
|
||||
$WorldAvatarEntityService,
|
||||
|
||||
$ApAudienceService,
|
||||
$ApDbResolverService,
|
||||
|
||||
130
packages/backend/src/core/WorldAvatarService.ts
Normal file
130
packages/backend/src/core/WorldAvatarService.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { DataSource, In, Not } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import {
|
||||
MiDriveFile,
|
||||
MiWorldAvatar,
|
||||
} from '@/models/_.js';
|
||||
import type { DriveFilesRepository, WorldAvatarsRepository } from '@/models/_.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { QueryService } from '@/core/QueryService.js';
|
||||
|
||||
@Injectable()
|
||||
export class WorldAvatarService {
|
||||
constructor(
|
||||
@Inject(DI.db)
|
||||
private db: DataSource,
|
||||
|
||||
@Inject(DI.worldAvatarsRepository)
|
||||
private worldAvatarsRepository: WorldAvatarsRepository,
|
||||
|
||||
private roleService: RoleService,
|
||||
private moderationLogService: ModerationLogService,
|
||||
private queryService: QueryService,
|
||||
private idService: IdService,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async validateDef(
|
||||
me: MiUser,
|
||||
def: MiWorldAvatar['def'],
|
||||
): Promise<boolean> {
|
||||
// TODO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async findMyAvatarById(userId: MiUser['id'], avatarId: MiWorldAvatar['id']) {
|
||||
return this.worldAvatarsRepository.findOneBy({ id: avatarId, userId: userId });
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async findAvatarById(avatarId: MiWorldAvatar['id']) {
|
||||
return this.worldAvatarsRepository.findOne({ where: { id: avatarId }, relations: ['user'] });
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getMyAvatarsWithPagination(userId: MiUser['id'], limit: number, sinceId?: MiWorldAvatar['id'] | null, untilId?: MiWorldAvatar['id'] | null) {
|
||||
const query = this.queryService.makePaginationQuery(this.worldAvatarsRepository.createQueryBuilder('avatar'), sinceId, untilId)
|
||||
.andWhere('avatar.userId = :userId', { userId });
|
||||
|
||||
const avatars = await query.take(limit).getMany();
|
||||
|
||||
return avatars;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async create(
|
||||
me: MiUser,
|
||||
body: Partial<MiWorldAvatar>,
|
||||
): Promise<MiWorldAvatar> {
|
||||
const currentAvatarsCount = await this.worldAvatarsRepository.countBy({ userId: me.id });
|
||||
|
||||
// TODO: limit by role policy
|
||||
|
||||
const avatar = await this.worldAvatarsRepository.insertOne(new MiWorldAvatar({
|
||||
id: this.idService.gen(),
|
||||
updatedAt: new Date(),
|
||||
name: body.name,
|
||||
def: body.def,
|
||||
userId: me.id,
|
||||
active: currentAvatarsCount === 0,
|
||||
}));
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async update(
|
||||
avatar: MiWorldAvatar,
|
||||
body: Partial<MiWorldAvatar>,
|
||||
): Promise<void> {
|
||||
body.updatedAt = new Date();
|
||||
const updated = await this.worldAvatarsRepository.createQueryBuilder().update()
|
||||
.set(body)
|
||||
.where('id = :id', { id: avatar.id })
|
||||
.returning('*')
|
||||
.execute()
|
||||
.then((response) => {
|
||||
return response.raw[0];
|
||||
});
|
||||
|
||||
if (body.active) {
|
||||
await this.worldAvatarsRepository.createQueryBuilder().update()
|
||||
.set({ active: false })
|
||||
.where('userId = :userId', { userId: avatar.userId })
|
||||
.andWhere('id != :id', { id: avatar.id })
|
||||
.execute();
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async delete(avatar: MiWorldAvatar, deleter?: MiUser): Promise<void> {
|
||||
await this.worldAvatarsRepository.delete(avatar.id);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getActiveAvatarOfUser(userId: MiUser['id']) {
|
||||
return this.worldAvatarsRepository.findOneBy({ userId, active: true });
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getActiveAvatarOfUsers(userIds: MiUser['id'][]): Promise<MiWorldAvatar[]> {
|
||||
if (userIds.length === 0) return [];
|
||||
return this.worldAvatarsRepository.findBy({ userId: In(userIds), active: true });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { DriveFilesRepository, MiWorldAvatar, WorldAvatarsRepository } from '@/models/_.js';
|
||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||
import type { Packed } from '@/misc/json-schema.js';
|
||||
import type { } from '@/models/Blocking.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { WorldAvatarService } from '@/core/WorldAvatarService.js';
|
||||
import { UserEntityService } from './UserEntityService.js';
|
||||
import { DriveFileEntityService } from './DriveFileEntityService.js';
|
||||
import { In } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class WorldAvatarEntityService {
|
||||
constructor(
|
||||
@Inject(DI.worldAvatarsRepository)
|
||||
private worldAvatarsRepository: WorldAvatarsRepository,
|
||||
|
||||
private worldAvatarService: WorldAvatarService,
|
||||
private userEntityService: UserEntityService,
|
||||
private idService: IdService,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async packLite(
|
||||
src: MiWorldAvatar['id'] | MiWorldAvatar,
|
||||
me?: { id: MiUser['id'] } | null | undefined,
|
||||
hint?: {
|
||||
packedUser?: Packed<'UserLite'>
|
||||
},
|
||||
): Promise<Packed<'WorldAvatarLite'>> {
|
||||
const meId = me ? me.id : null;
|
||||
const avatar = typeof src === 'object' ? src : await this.worldAvatarsRepository.findOneByOrFail({ id: src });
|
||||
|
||||
return await awaitAll({
|
||||
id: avatar.id,
|
||||
def: avatar.def,
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async packDetailed(
|
||||
src: MiWorldAvatar['id'] | MiWorldAvatar,
|
||||
me?: { id: MiUser['id'] } | null | undefined,
|
||||
hint?: {
|
||||
packedUser?: Packed<'UserLite'>
|
||||
},
|
||||
): Promise<Packed<'WorldAvatarDetailed'>> {
|
||||
const meId = me ? me.id : null;
|
||||
const avatar = typeof src === 'object' ? src : await this.worldAvatarsRepository.findOneByOrFail({ id: src });
|
||||
|
||||
return await awaitAll({
|
||||
id: avatar.id,
|
||||
createdAt: this.idService.parse(avatar.id).date.toISOString(),
|
||||
updatedAt: avatar.updatedAt.toISOString(),
|
||||
name: avatar.name,
|
||||
def: avatar.def,
|
||||
active: avatar.active,
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async packLiteMany(
|
||||
avatars: MiWorldAvatar[],
|
||||
me?: { id: MiUser['id'] } | null | undefined,
|
||||
) {
|
||||
const _users = avatars.map(({ user, userId }) => user ?? userId);
|
||||
const _userMap = await this.userEntityService.packMany(_users, me)
|
||||
.then(users => new Map(users.map(u => [u.id, u])));
|
||||
return Promise.all(avatars.map(avatar => this.packLite(avatar, me, { packedUser: _userMap.get(avatar.userId) })));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,5 +92,6 @@ export const DI = {
|
||||
reversiGamesRepository: Symbol('reversiGamesRepository'),
|
||||
noteDraftsRepository: Symbol('noteDraftsRepository'),
|
||||
worldRoomsRepository: Symbol('worldRoomsRepository'),
|
||||
worldAvatarsRepository: Symbol('worldAvatarsRepository'),
|
||||
//#endregion
|
||||
};
|
||||
|
||||
@@ -76,6 +76,7 @@ import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-m
|
||||
import { packedAchievementNameSchema, packedAchievementSchema } from '@/models/json-schema/achievement.js';
|
||||
import { packedNoteDraftSchema } from '@/models/json-schema/note-draft.js';
|
||||
import { packedWorldRoomDetailedSchema, packedWorldRoomLiteSchema } from '@/models/json-schema/world-room.js';
|
||||
import { packedWorldAvatarDetailedSchema, packedWorldAvatarLiteSchema } from '@/models/json-schema/world-avatar.js';
|
||||
|
||||
export const refs = {
|
||||
UserLite: packedUserLiteSchema,
|
||||
@@ -150,6 +151,8 @@ export const refs = {
|
||||
ChatRoomMembership: packedChatRoomMembershipSchema,
|
||||
WorldRoomLite: packedWorldRoomLiteSchema,
|
||||
WorldRoomDetailed: packedWorldRoomDetailedSchema,
|
||||
WorldAvatarLite: packedWorldAvatarLiteSchema,
|
||||
WorldAvatarDetailed: packedWorldAvatarDetailedSchema,
|
||||
};
|
||||
|
||||
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
|
||||
|
||||
@@ -85,6 +85,7 @@ import {
|
||||
MiChatRoomInvitation,
|
||||
MiChatApproval,
|
||||
MiWorldRoom,
|
||||
MiWorldAvatar,
|
||||
} from './_.js';
|
||||
import type { Provider } from '@nestjs/common';
|
||||
import type { DataSource } from 'typeorm';
|
||||
@@ -551,6 +552,12 @@ const $worldRoomsRepository: Provider = {
|
||||
inject: [DI.db],
|
||||
};
|
||||
|
||||
const $worldAvatarsRepository: Provider = {
|
||||
provide: DI.worldAvatarsRepository,
|
||||
useFactory: (db: DataSource) => db.getRepository(MiWorldAvatar).extend(miRepository as MiRepository<MiWorldAvatar>),
|
||||
inject: [DI.db],
|
||||
};
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
providers: [
|
||||
@@ -631,6 +638,7 @@ const $worldRoomsRepository: Provider = {
|
||||
$bubbleGameRecordsRepository,
|
||||
$reversiGamesRepository,
|
||||
$worldRoomsRepository,
|
||||
$worldAvatarsRepository,
|
||||
],
|
||||
exports: [
|
||||
$usersRepository,
|
||||
@@ -710,6 +718,7 @@ const $worldRoomsRepository: Provider = {
|
||||
$bubbleGameRecordsRepository,
|
||||
$reversiGamesRepository,
|
||||
$worldRoomsRepository,
|
||||
$worldAvatarsRepository,
|
||||
],
|
||||
})
|
||||
export class RepositoryModule {
|
||||
|
||||
54
packages/backend/src/models/WorldAvatar.ts
Normal file
54
packages/backend/src/models/WorldAvatar.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
|
||||
import { id } from './util/id.js';
|
||||
import { MiUser } from './User.js';
|
||||
|
||||
@Entity('world_avatar')
|
||||
export class MiWorldAvatar {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column('timestamp with time zone', {
|
||||
})
|
||||
public updatedAt: Date;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 256,
|
||||
})
|
||||
public name: string;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
})
|
||||
public userId: MiUser['id'];
|
||||
|
||||
@ManyToOne(() => MiUser, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: MiUser | null;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public active: boolean;
|
||||
|
||||
@Column('jsonb', {
|
||||
default: {},
|
||||
})
|
||||
public def: Record<string, any>;
|
||||
|
||||
constructor(data: Partial<MiWorldAvatar>) {
|
||||
if (data == null) return;
|
||||
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
(this as any)[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,11 @@ export class MiWorldRoom {
|
||||
})
|
||||
public likedCount: number;
|
||||
|
||||
@Column('integer', {
|
||||
default: 0,
|
||||
})
|
||||
public accessCount: number;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128, default: 'public',
|
||||
})
|
||||
|
||||
@@ -85,6 +85,7 @@ import { MiUserPublickey } from '@/models/UserPublickey.js';
|
||||
import { MiUserSecurityKey } from '@/models/UserSecurityKey.js';
|
||||
import { MiWebhook } from '@/models/Webhook.js';
|
||||
import { MiWorldRoom } from '@/models/WorldRoom.js';
|
||||
import { MiWorldAvatar } from '@/models/WorldAvatar.js';
|
||||
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
|
||||
|
||||
export interface MiRepository<T extends ObjectLiteral> {
|
||||
@@ -175,6 +176,7 @@ export {
|
||||
MiBubbleGameRecord,
|
||||
MiReversiGame,
|
||||
MiWorldRoom,
|
||||
MiWorldAvatar,
|
||||
};
|
||||
|
||||
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
|
||||
@@ -256,3 +258,4 @@ export type ChatApprovalsRepository = Repository<MiChatApproval> & MiRepository<
|
||||
export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord> & MiRepository<MiBubbleGameRecord>;
|
||||
export type ReversiGamesRepository = Repository<MiReversiGame> & MiRepository<MiReversiGame>;
|
||||
export type WorldRoomsRepository = Repository<MiWorldRoom> & MiRepository<MiWorldRoom>;
|
||||
export type WorldAvatarsRepository = Repository<MiWorldAvatar> & MiRepository<MiWorldAvatar>;
|
||||
|
||||
52
packages/backend/src/models/json-schema/world-avatar.ts
Normal file
52
packages/backend/src/models/json-schema/world-avatar.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export const packedWorldAvatarLiteSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
def: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const packedWorldAvatarDetailedSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
def: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
active: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
@@ -88,6 +88,7 @@ import { MiReversiGame } from '@/models/ReversiGame.js';
|
||||
import { MiChatApproval } from '@/models/ChatApproval.js';
|
||||
import { MiSystemAccount } from '@/models/SystemAccount.js';
|
||||
import { MiWorldRoom } from '@/models/WorldRoom.js';
|
||||
import { MiWorldAvatar } from '@/models/WorldAvatar.js';
|
||||
|
||||
pg.types.setTypeParser(20, Number);
|
||||
|
||||
@@ -256,6 +257,7 @@ export const entities = [
|
||||
MiBubbleGameRecord,
|
||||
MiReversiGame,
|
||||
MiWorldRoom,
|
||||
MiWorldAvatar,
|
||||
...charts,
|
||||
];
|
||||
|
||||
|
||||
@@ -448,4 +448,9 @@ export * as 'world/rooms/update' from './endpoints/world/rooms/update.js';
|
||||
export * as 'world/rooms/delete' from './endpoints/world/rooms/delete.js';
|
||||
export * as 'world/rooms/list-by-user' from './endpoints/world/rooms/list-by-user.js';
|
||||
export * as 'world/rooms/show' from './endpoints/world/rooms/show.js';
|
||||
export * as 'world/avatars/create' from './endpoints/world/avatars/create.js';
|
||||
export * as 'world/avatars/update' from './endpoints/world/avatars/update.js';
|
||||
export * as 'world/avatars/delete' from './endpoints/world/avatars/delete.js';
|
||||
export * as 'world/avatars/list' from './endpoints/world/avatars/list.js';
|
||||
export * as 'world/avatars/show' from './endpoints/world/avatars/show.js';
|
||||
export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js';
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 { WorldAvatarService } from '@/core/WorldAvatarService.js';
|
||||
import { WorldAvatarEntityService } from '@/core/entities/WorldAvatarEntityService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['worldAvatar'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
kind: 'write:worldAvatar',
|
||||
|
||||
limit: {
|
||||
duration: ms('1day'),
|
||||
max: 10,
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'WorldAvatarDetailed',
|
||||
},
|
||||
|
||||
errors: {
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', maxLength: 256 },
|
||||
def: { type: 'object', additionalProperties: true },
|
||||
},
|
||||
required: ['name', 'def'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private worldAvatarService: WorldAvatarService,
|
||||
private worldAvatarEntityService: WorldAvatarEntityService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
// TODO: validate avatar
|
||||
|
||||
const avatar = await this.worldAvatarService.create(me, {
|
||||
name: ps.name,
|
||||
def: ps.def,
|
||||
});
|
||||
return await this.worldAvatarEntityService.packDetailed(avatar);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 { WorldAvatarService } from '@/core/WorldAvatarService.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['worldAvatar'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:worldAvatar',
|
||||
|
||||
errors: {
|
||||
noSuchAvatar: {
|
||||
message: 'No such avatar.',
|
||||
code: 'NO_SUCH_ROOM',
|
||||
id: 'd4e3753d-97bf-4a19-ab8e-21080fbc0f4c',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
avatarId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['avatarId'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private worldAvatarService: WorldAvatarService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const avatar = await this.worldAvatarService.findMyAvatarById(me.id, ps.avatarId);
|
||||
if (avatar == null) {
|
||||
throw new ApiError(meta.errors.noSuchAvatar);
|
||||
}
|
||||
|
||||
await this.worldAvatarService.delete(avatar, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 { WorldAvatarService } from '@/core/WorldAvatarService.js';
|
||||
import { WorldAvatarEntityService } from '@/core/entities/WorldAvatarEntityService.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['worldAvatar'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'read:worldAvatar',
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'WorldAvatarLite',
|
||||
},
|
||||
},
|
||||
|
||||
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' },
|
||||
sinceDate: { type: 'integer' },
|
||||
untilDate: { type: 'integer' },
|
||||
},
|
||||
required: ['userId'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private worldAvatarEntityService: WorldAvatarEntityService,
|
||||
private worldAvatarService: WorldAvatarService,
|
||||
private idService: IdService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
||||
|
||||
const avatars = await this.worldAvatarService.getMyAvatarsWithPagination(ps.userId, ps.limit, sinceId, untilId);
|
||||
return this.worldAvatarEntityService.packLiteMany(avatars, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 { WorldAvatarService } from '@/core/WorldAvatarService.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
import { WorldAvatarEntityService } from '@/core/entities/WorldAvatarEntityService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['worldAvatar'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'read:worldAvatar',
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'WorldAvatarDetailed',
|
||||
},
|
||||
|
||||
errors: {
|
||||
noSuchAvatar: {
|
||||
message: 'No such avatar.',
|
||||
code: 'NO_SUCH_ROOM',
|
||||
id: '857ae02f-8759-4d20-9adb-6e95fffe4fd8',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
avatarId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['avatarId'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private worldAvatarService: WorldAvatarService,
|
||||
private worldAvatarEntityService: WorldAvatarEntityService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const avatar = await this.worldAvatarService.findAvatarById(ps.avatarId);
|
||||
if (avatar == null) {
|
||||
throw new ApiError(meta.errors.noSuchAvatar);
|
||||
}
|
||||
|
||||
if (avatar.userId !== me.id) {
|
||||
throw new ApiError(meta.errors.noSuchAvatar);
|
||||
}
|
||||
|
||||
return this.worldAvatarEntityService.packDetailed(avatar, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 { WorldAvatarService } from '@/core/WorldAvatarService.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['worldAvatar'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'write:worldAvatar',
|
||||
|
||||
res: {
|
||||
},
|
||||
|
||||
errors: {
|
||||
noSuchAvatar: {
|
||||
message: 'No such avatar.',
|
||||
code: 'NO_SUCH_ROOM',
|
||||
id: 'fcdb0f92-bda6-47f9-bd05-343e0e020933',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
avatarId: { type: 'string', format: 'misskey:id' },
|
||||
name: { type: 'string', maxLength: 256 },
|
||||
def: { type: 'object', additionalProperties: true },
|
||||
active: { type: 'boolean' },
|
||||
},
|
||||
required: ['avatarId'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private worldAvatarService: WorldAvatarService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const avatar = await this.worldAvatarService.findMyAvatarById(me.id, ps.avatarId);
|
||||
if (avatar == null) {
|
||||
throw new ApiError(meta.errors.noSuchAvatar);
|
||||
}
|
||||
|
||||
// TODO: validate avatar
|
||||
|
||||
await this.worldAvatarService.update(avatar, {
|
||||
name: ps.name,
|
||||
def: ps.def,
|
||||
active: ps.active,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -924,6 +924,27 @@ export type Channels = {
|
||||
};
|
||||
};
|
||||
};
|
||||
worldRoom: {
|
||||
params: {
|
||||
roomId: string;
|
||||
};
|
||||
events: {
|
||||
entered: (payload: {
|
||||
playerProfiles: any;
|
||||
}) => void;
|
||||
sync: (payload: any) => void;
|
||||
playerEntered: (payload: {
|
||||
id: string;
|
||||
profile: any;
|
||||
}) => void;
|
||||
playerLeft: (payload: {
|
||||
id: string;
|
||||
}) => void;
|
||||
};
|
||||
receives: {
|
||||
update: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -2183,6 +2204,15 @@ declare namespace entities {
|
||||
V2AdminEmojiListRequest,
|
||||
V2AdminEmojiListResponse,
|
||||
VerifyEmailRequest,
|
||||
WorldAvatarsCreateRequest,
|
||||
WorldAvatarsCreateResponse,
|
||||
WorldAvatarsDeleteRequest,
|
||||
WorldAvatarsListRequest,
|
||||
WorldAvatarsListResponse,
|
||||
WorldAvatarsShowRequest,
|
||||
WorldAvatarsShowResponse,
|
||||
WorldAvatarsUpdateRequest,
|
||||
WorldAvatarsUpdateResponse,
|
||||
WorldRoomsCreateRequest,
|
||||
WorldRoomsCreateResponse,
|
||||
WorldRoomsDeleteRequest,
|
||||
@@ -2263,7 +2293,9 @@ declare namespace entities {
|
||||
ChatRoomInvitation,
|
||||
ChatRoomMembership,
|
||||
WorldRoomLite,
|
||||
WorldRoomDetailed
|
||||
WorldRoomDetailed,
|
||||
WorldAvatarLite,
|
||||
WorldAvatarDetailed
|
||||
}
|
||||
}
|
||||
export { entities }
|
||||
@@ -3912,6 +3944,39 @@ type V2AdminEmojiListResponse = operations['v2___admin___emoji___list']['respons
|
||||
// @public (undocumented)
|
||||
type VerifyEmailRequest = operations['verify-email']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarDetailed = components['schemas']['WorldAvatarDetailed'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarLite = components['schemas']['WorldAvatarLite'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsCreateRequest = operations['world___avatars___create']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsCreateResponse = operations['world___avatars___create']['responses']['200']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsDeleteRequest = operations['world___avatars___delete']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsListRequest = operations['world___avatars___list']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsListResponse = operations['world___avatars___list']['responses']['200']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsShowRequest = operations['world___avatars___show']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsShowResponse = operations['world___avatars___show']['responses']['200']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsUpdateRequest = operations['world___avatars___update']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldAvatarsUpdateResponse = operations['world___avatars___update']['responses']['200']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type WorldRoomDetailed = components['schemas']['WorldRoomDetailed'];
|
||||
|
||||
|
||||
@@ -4829,6 +4829,61 @@ declare module '../api.js' {
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *write:worldAvatar*
|
||||
*/
|
||||
request<E extends 'world/avatars/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:worldAvatar*
|
||||
*/
|
||||
request<E extends 'world/avatars/delete', P extends Endpoints[E]['req']>(
|
||||
endpoint: E,
|
||||
params: P,
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *read:worldAvatar*
|
||||
*/
|
||||
request<E extends 'world/avatars/list', P extends Endpoints[E]['req']>(
|
||||
endpoint: E,
|
||||
params: P,
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *read:worldAvatar*
|
||||
*/
|
||||
request<E extends 'world/avatars/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:worldAvatar*
|
||||
*/
|
||||
request<E extends 'world/avatars/update', P extends Endpoints[E]['req']>(
|
||||
endpoint: E,
|
||||
params: P,
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
|
||||
@@ -661,6 +661,15 @@ import type {
|
||||
V2AdminEmojiListRequest,
|
||||
V2AdminEmojiListResponse,
|
||||
VerifyEmailRequest,
|
||||
WorldAvatarsCreateRequest,
|
||||
WorldAvatarsCreateResponse,
|
||||
WorldAvatarsDeleteRequest,
|
||||
WorldAvatarsListRequest,
|
||||
WorldAvatarsListResponse,
|
||||
WorldAvatarsShowRequest,
|
||||
WorldAvatarsShowResponse,
|
||||
WorldAvatarsUpdateRequest,
|
||||
WorldAvatarsUpdateResponse,
|
||||
WorldRoomsCreateRequest,
|
||||
WorldRoomsCreateResponse,
|
||||
WorldRoomsDeleteRequest,
|
||||
@@ -1107,6 +1116,11 @@ export type Endpoints = {
|
||||
'users/update-memo': { req: UsersUpdateMemoRequest; res: EmptyResponse };
|
||||
'v2/admin/emoji/list': { req: V2AdminEmojiListRequest; res: V2AdminEmojiListResponse };
|
||||
'verify-email': { req: VerifyEmailRequest; res: EmptyResponse };
|
||||
'world/avatars/create': { req: WorldAvatarsCreateRequest; res: WorldAvatarsCreateResponse };
|
||||
'world/avatars/delete': { req: WorldAvatarsDeleteRequest; res: EmptyResponse };
|
||||
'world/avatars/list': { req: WorldAvatarsListRequest; res: WorldAvatarsListResponse };
|
||||
'world/avatars/show': { req: WorldAvatarsShowRequest; res: WorldAvatarsShowResponse };
|
||||
'world/avatars/update': { req: WorldAvatarsUpdateRequest; res: WorldAvatarsUpdateResponse };
|
||||
'world/rooms/create': { req: WorldRoomsCreateRequest; res: WorldRoomsCreateResponse };
|
||||
'world/rooms/delete': { req: WorldRoomsDeleteRequest; res: EmptyResponse };
|
||||
'world/rooms/list-by-user': { req: WorldRoomsListByUserRequest; res: WorldRoomsListByUserResponse };
|
||||
|
||||
@@ -664,6 +664,15 @@ export type UsersUpdateMemoRequest = operations['users___update-memo']['requestB
|
||||
export type V2AdminEmojiListRequest = operations['v2___admin___emoji___list']['requestBody']['content']['application/json'];
|
||||
export type V2AdminEmojiListResponse = operations['v2___admin___emoji___list']['responses']['200']['content']['application/json'];
|
||||
export type VerifyEmailRequest = operations['verify-email']['requestBody']['content']['application/json'];
|
||||
export type WorldAvatarsCreateRequest = operations['world___avatars___create']['requestBody']['content']['application/json'];
|
||||
export type WorldAvatarsCreateResponse = operations['world___avatars___create']['responses']['200']['content']['application/json'];
|
||||
export type WorldAvatarsDeleteRequest = operations['world___avatars___delete']['requestBody']['content']['application/json'];
|
||||
export type WorldAvatarsListRequest = operations['world___avatars___list']['requestBody']['content']['application/json'];
|
||||
export type WorldAvatarsListResponse = operations['world___avatars___list']['responses']['200']['content']['application/json'];
|
||||
export type WorldAvatarsShowRequest = operations['world___avatars___show']['requestBody']['content']['application/json'];
|
||||
export type WorldAvatarsShowResponse = operations['world___avatars___show']['responses']['200']['content']['application/json'];
|
||||
export type WorldAvatarsUpdateRequest = operations['world___avatars___update']['requestBody']['content']['application/json'];
|
||||
export type WorldAvatarsUpdateResponse = operations['world___avatars___update']['responses']['200']['content']['application/json'];
|
||||
export type WorldRoomsCreateRequest = operations['world___rooms___create']['requestBody']['content']['application/json'];
|
||||
export type WorldRoomsCreateResponse = operations['world___rooms___create']['responses']['200']['content']['application/json'];
|
||||
export type WorldRoomsDeleteRequest = operations['world___rooms___delete']['requestBody']['content']['application/json'];
|
||||
|
||||
@@ -71,3 +71,5 @@ export type ChatRoomInvitation = components['schemas']['ChatRoomInvitation'];
|
||||
export type ChatRoomMembership = components['schemas']['ChatRoomMembership'];
|
||||
export type WorldRoomLite = components['schemas']['WorldRoomLite'];
|
||||
export type WorldRoomDetailed = components['schemas']['WorldRoomDetailed'];
|
||||
export type WorldAvatarLite = components['schemas']['WorldAvatarLite'];
|
||||
export type WorldAvatarDetailed = components['schemas']['WorldAvatarDetailed'];
|
||||
|
||||
@@ -3960,6 +3960,51 @@ export type paths = {
|
||||
*/
|
||||
post: operations['verify-email'];
|
||||
};
|
||||
'/world/avatars/create': {
|
||||
/**
|
||||
* world/avatars/create
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *write:worldAvatar*
|
||||
*/
|
||||
post: operations['world___avatars___create'];
|
||||
};
|
||||
'/world/avatars/delete': {
|
||||
/**
|
||||
* world/avatars/delete
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *write:worldAvatar*
|
||||
*/
|
||||
post: operations['world___avatars___delete'];
|
||||
};
|
||||
'/world/avatars/list': {
|
||||
/**
|
||||
* world/avatars/list
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *read:worldAvatar*
|
||||
*/
|
||||
post: operations['world___avatars___list'];
|
||||
};
|
||||
'/world/avatars/show': {
|
||||
/**
|
||||
* world/avatars/show
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *read:worldAvatar*
|
||||
*/
|
||||
post: operations['world___avatars___show'];
|
||||
};
|
||||
'/world/avatars/update': {
|
||||
/**
|
||||
* world/avatars/update
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *write:worldAvatar*
|
||||
*/
|
||||
post: operations['world___avatars___update'];
|
||||
};
|
||||
'/world/rooms/create': {
|
||||
/**
|
||||
* world/rooms/create
|
||||
@@ -5761,6 +5806,22 @@ export type components = {
|
||||
def: Record<string, never>;
|
||||
attachedFiles: components['schemas']['DriveFile'][];
|
||||
};
|
||||
WorldAvatarLite: {
|
||||
/** Format: id */
|
||||
id: string;
|
||||
def: Record<string, never>;
|
||||
};
|
||||
WorldAvatarDetailed: {
|
||||
/** Format: id */
|
||||
id: string;
|
||||
/** Format: date-time */
|
||||
createdAt: string;
|
||||
/** Format: date-time */
|
||||
updatedAt: string;
|
||||
name: string;
|
||||
def: Record<string, never>;
|
||||
active: boolean;
|
||||
};
|
||||
};
|
||||
responses: never;
|
||||
parameters: never;
|
||||
@@ -37023,6 +37084,355 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
world___avatars___create: {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
name: string;
|
||||
def: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['WorldAvatarDetailed'];
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Too many requests */
|
||||
429: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
world___avatars___delete: {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
/** Format: misskey:id */
|
||||
avatarId: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (without any results) */
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
world___avatars___list: {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
/** @default 30 */
|
||||
limit?: number;
|
||||
/** Format: misskey:id */
|
||||
sinceId?: string;
|
||||
/** Format: misskey:id */
|
||||
untilId?: string;
|
||||
sinceDate?: number;
|
||||
untilDate?: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['WorldAvatarLite'][];
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
world___avatars___show: {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
/** Format: misskey:id */
|
||||
avatarId: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['WorldAvatarDetailed'];
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
world___avatars___update: {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
/** Format: misskey:id */
|
||||
avatarId: string;
|
||||
name?: string;
|
||||
def?: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
active?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': unknown;
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
world___rooms___create: {
|
||||
requestBody: {
|
||||
content: {
|
||||
|
||||
24
packages/misskey-world/src/types.ts
Normal file
24
packages/misskey-world/src/types.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export type WorldAvatar = {
|
||||
type: 'default';
|
||||
body: {
|
||||
color: [number, number, number];
|
||||
roughness: number;
|
||||
metallic: number;
|
||||
};
|
||||
eyes: {
|
||||
type: string;
|
||||
color: [number, number, number];
|
||||
};
|
||||
mouth: {
|
||||
type: string;
|
||||
color: [number, number, number];
|
||||
};
|
||||
accessories: {
|
||||
type: string;
|
||||
}[];
|
||||
};
|
||||
Reference in New Issue
Block a user