merge: upstream
This commit is contained in:
commit
11628e4b6a
285 changed files with 3413 additions and 1913 deletions
|
@ -3,6 +3,6 @@ import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
|
|||
import { writeFileSync } from "node:fs";
|
||||
|
||||
const config = loadConfig();
|
||||
const spec = genOpenapiSpec(config);
|
||||
const spec = genOpenapiSpec(config, true);
|
||||
|
||||
writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class FixMetaDisableRegistration1706791962000 {
|
||||
name = 'FixMetaDisableRegistration1706791962000'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`alter table meta alter column "disableRegistration" set default true;`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`alter table meta alter column "disableRegistration" set default false;`);
|
||||
}
|
||||
}
|
|
@ -65,9 +65,9 @@
|
|||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.412.0",
|
||||
"@aws-sdk/lib-storage": "3.412.0",
|
||||
"@bull-board/api": "5.10.2",
|
||||
"@bull-board/fastify": "5.10.2",
|
||||
"@bull-board/ui": "5.10.2",
|
||||
"@bull-board/api": "5.14.0",
|
||||
"@bull-board/fastify": "5.14.0",
|
||||
"@bull-board/ui": "5.14.0",
|
||||
"@discordapp/twemoji": "15.0.2",
|
||||
"@fastify/accepts": "4.3.0",
|
||||
"@fastify/cookie": "9.3.1",
|
||||
|
@ -84,11 +84,11 @@
|
|||
"@nestjs/testing": "10.2.10",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@transfem-org/sfm-js": "0.24.4",
|
||||
"@simplewebauthn/server": "9.0.0",
|
||||
"@simplewebauthn/server": "9.0.1",
|
||||
"@sinonjs/fake-timers": "11.2.2",
|
||||
"@smithy/node-http-handler": "2.1.10",
|
||||
"@swc/cli": "0.1.63",
|
||||
"@swc/core": "1.3.105",
|
||||
"@swc/core": "1.3.107",
|
||||
"@twemoji/parser": "15.0.0",
|
||||
"accepts": "1.3.8",
|
||||
"ajv": "8.12.0",
|
||||
|
@ -98,7 +98,7 @@
|
|||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.5",
|
||||
"body-parser": "1.20.2",
|
||||
"bullmq": "5.1.4",
|
||||
"bullmq": "5.1.5",
|
||||
"cacheable-lookup": "7.0.0",
|
||||
"cbor": "9.0.1",
|
||||
"chalk": "5.3.0",
|
||||
|
@ -117,7 +117,7 @@
|
|||
"fluent-ffmpeg": "2.1.2",
|
||||
"form-data": "4.0.0",
|
||||
"glob": "10.3.10",
|
||||
"got": "14.0.0",
|
||||
"got": "14.1.0",
|
||||
"happy-dom": "10.0.3",
|
||||
"hpagent": "1.2.0",
|
||||
"http-link-header": "1.1.1",
|
||||
|
@ -148,7 +148,7 @@
|
|||
"otpauth": "9.2.2",
|
||||
"parse5": "7.1.2",
|
||||
"pg": "8.11.3",
|
||||
"pkce-challenge": "4.0.1",
|
||||
"pkce-challenge": "4.1.0",
|
||||
"probe-image-size": "7.2.3",
|
||||
"promise-limit": "2.7.0",
|
||||
"pug": "3.0.2",
|
||||
|
@ -169,12 +169,12 @@
|
|||
"slacc": "0.0.10",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"systeminformation": "5.21.23",
|
||||
"systeminformation": "5.21.24",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tmp": "0.2.1",
|
||||
"tsc-alias": "1.8.8",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typeorm": "0.3.19",
|
||||
"typeorm": "0.3.20",
|
||||
"typescript": "5.3.3",
|
||||
"ulid": "2.3.0",
|
||||
"uuid": "^9.0.1",
|
||||
|
@ -186,7 +186,7 @@
|
|||
"devDependencies": {
|
||||
"@jest/globals": "29.7.0",
|
||||
"@misskey-dev/eslint-plugin": "1.0.0",
|
||||
"@nestjs/platform-express": "10.3.0",
|
||||
"@nestjs/platform-express": "10.3.1",
|
||||
"@simplewebauthn/typescript-types": "8.3.4",
|
||||
"@swc/jest": "0.2.31",
|
||||
"@types/accepts": "1.3.7",
|
||||
|
@ -205,13 +205,13 @@
|
|||
"@types/jsrsasign": "10.5.12",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/ms": "0.7.34",
|
||||
"@types/node": "20.11.5",
|
||||
"@types/node": "20.11.10",
|
||||
"@types/node-fetch": "3.0.3",
|
||||
"@types/nodemailer": "6.4.14",
|
||||
"@types/oauth": "0.9.4",
|
||||
"@types/oauth2orize": "1.11.3",
|
||||
"@types/oauth2orize-pkce": "0.1.2",
|
||||
"@types/pg": "8.10.9",
|
||||
"@types/pg": "8.11.0",
|
||||
"@types/pug": "2.0.10",
|
||||
"@types/punycode": "2.1.3",
|
||||
"@types/qrcode": "1.5.5",
|
||||
|
|
|
@ -76,10 +76,10 @@ type Source = {
|
|||
|
||||
deliverJobConcurrency?: number;
|
||||
inboxJobConcurrency?: number;
|
||||
relashionshipJobConcurrency?: number;
|
||||
relationshipJobConcurrency?: number;
|
||||
deliverJobPerSec?: number;
|
||||
inboxJobPerSec?: number;
|
||||
relashionshipJobPerSec?: number;
|
||||
relationshipJobPerSec?: number;
|
||||
deliverJobMaxAttempts?: number;
|
||||
inboxJobMaxAttempts?: number;
|
||||
|
||||
|
@ -141,10 +141,10 @@ export type Config = {
|
|||
outgoingAddressFamily: 'ipv4' | 'ipv6' | 'dual' | undefined;
|
||||
deliverJobConcurrency: number | undefined;
|
||||
inboxJobConcurrency: number | undefined;
|
||||
relashionshipJobConcurrency: number | undefined;
|
||||
relationshipJobConcurrency: number | undefined;
|
||||
deliverJobPerSec: number | undefined;
|
||||
inboxJobPerSec: number | undefined;
|
||||
relashionshipJobPerSec: number | undefined;
|
||||
relationshipJobPerSec: number | undefined;
|
||||
deliverJobMaxAttempts: number | undefined;
|
||||
inboxJobMaxAttempts: number | undefined;
|
||||
proxyRemoteFiles: boolean | undefined;
|
||||
|
@ -257,10 +257,10 @@ export function loadConfig(): Config {
|
|||
outgoingAddressFamily: config.outgoingAddressFamily,
|
||||
deliverJobConcurrency: config.deliverJobConcurrency,
|
||||
inboxJobConcurrency: config.inboxJobConcurrency,
|
||||
relashionshipJobConcurrency: config.relashionshipJobConcurrency,
|
||||
relationshipJobConcurrency: config.relationshipJobConcurrency,
|
||||
deliverJobPerSec: config.deliverJobPerSec,
|
||||
inboxJobPerSec: config.inboxJobPerSec,
|
||||
relashionshipJobPerSec: config.relashionshipJobPerSec,
|
||||
relationshipJobPerSec: config.relationshipJobPerSec,
|
||||
deliverJobMaxAttempts: config.deliverJobMaxAttempts,
|
||||
inboxJobMaxAttempts: config.inboxJobMaxAttempts,
|
||||
proxyRemoteFiles: config.proxyRemoteFiles,
|
||||
|
|
|
@ -96,7 +96,7 @@ export class AccountMoveService {
|
|||
await this.apDeliverManagerService.deliverToFollowers(src, moveAct);
|
||||
|
||||
// Publish meUpdated event
|
||||
const iObj = await this.userEntityService.pack<true, true>(src.id, src, { detail: true, includeSecrets: true });
|
||||
const iObj = await this.userEntityService.pack(src.id, src, { schema: 'MeDetailed', includeSecrets: true });
|
||||
this.globalEventService.publishMainStream(src.id, 'meUpdated', iObj);
|
||||
|
||||
// Unfollow after 24 hours
|
||||
|
|
|
@ -54,15 +54,15 @@ export interface MainEventTypes {
|
|||
reply: Packed<'Note'>;
|
||||
renote: Packed<'Note'>;
|
||||
follow: Packed<'UserDetailedNotMe'>;
|
||||
followed: Packed<'User'>;
|
||||
unfollow: Packed<'User'>;
|
||||
meUpdated: Packed<'User'>;
|
||||
followed: Packed<'UserLite'>;
|
||||
unfollow: Packed<'UserDetailedNotMe'>;
|
||||
meUpdated: Packed<'MeDetailed'>;
|
||||
pageEvent: {
|
||||
pageId: MiPage['id'];
|
||||
event: string;
|
||||
var: any;
|
||||
userId: MiUser['id'];
|
||||
user: Packed<'User'>;
|
||||
user: Packed<'UserDetailed'>;
|
||||
};
|
||||
urlUploadFinished: {
|
||||
marker?: string | null;
|
||||
|
@ -92,7 +92,7 @@ export interface MainEventTypes {
|
|||
};
|
||||
driveFileCreated: Packed<'DriveFile'>;
|
||||
readAntenna: MiAntenna;
|
||||
receiveFollowRequest: Packed<'User'>;
|
||||
receiveFollowRequest: Packed<'UserLite'>;
|
||||
announcementCreated: {
|
||||
announcement: Packed<'Announcement'>;
|
||||
};
|
||||
|
@ -143,8 +143,8 @@ type NoteStreamEventTypes = {
|
|||
};
|
||||
|
||||
export interface UserListEventTypes {
|
||||
userAdded: Packed<'User'>;
|
||||
userRemoved: Packed<'User'>;
|
||||
userAdded: Packed<'UserLite'>;
|
||||
userRemoved: Packed<'UserLite'>;
|
||||
}
|
||||
|
||||
export interface AntennaEventTypes {
|
||||
|
|
|
@ -109,13 +109,13 @@ export class UserBlockingService implements OnModuleInit {
|
|||
|
||||
if (this.userEntityService.isLocalUser(followee)) {
|
||||
this.userEntityService.pack(followee, followee, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
}).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed));
|
||||
}
|
||||
|
||||
if (this.userEntityService.isLocalUser(follower) && !silent) {
|
||||
this.userEntityService.pack(followee, follower, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}).then(async packed => {
|
||||
this.globalEventService.publishMainStream(follower.id, 'unfollow', packed);
|
||||
|
||||
|
|
|
@ -293,9 +293,9 @@ export class UserFollowingService implements OnModuleInit {
|
|||
if (this.userEntityService.isLocalUser(follower) && !silent) {
|
||||
// Publish follow event
|
||||
this.userEntityService.pack(followee.id, follower, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}).then(async packed => {
|
||||
this.globalEventService.publishMainStream(follower.id, 'follow', packed as Packed<'UserDetailedNotMe'>);
|
||||
this.globalEventService.publishMainStream(follower.id, 'follow', packed);
|
||||
|
||||
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('follow'));
|
||||
for (const webhook of webhooks) {
|
||||
|
@ -360,7 +360,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||
if (!silent && this.userEntityService.isLocalUser(follower)) {
|
||||
// Publish unfollow event
|
||||
this.userEntityService.pack(followee.id, follower, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}).then(async packed => {
|
||||
this.globalEventService.publishMainStream(follower.id, 'unfollow', packed);
|
||||
|
||||
|
@ -500,7 +500,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||
this.userEntityService.pack(follower.id, followee).then(packed => this.globalEventService.publishMainStream(followee.id, 'receiveFollowRequest', packed));
|
||||
|
||||
this.userEntityService.pack(followee.id, followee, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
}).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed));
|
||||
|
||||
// 通知を作成
|
||||
|
@ -548,7 +548,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||
});
|
||||
|
||||
this.userEntityService.pack(followee.id, followee, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
}).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed));
|
||||
}
|
||||
|
||||
|
@ -576,7 +576,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||
}
|
||||
|
||||
this.userEntityService.pack(followee.id, followee, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
}).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed));
|
||||
}
|
||||
|
||||
|
@ -696,7 +696,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||
@bindThis
|
||||
private async publishUnfollow(followee: Both, follower: Local): Promise<void> {
|
||||
const packedFollowee = await this.userEntityService.pack(followee.id, follower, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
});
|
||||
|
||||
this.globalEventService.publishMainStream(follower.id, 'unfollow', packedFollowee);
|
||||
|
|
|
@ -94,6 +94,29 @@ type ToJsonSchema<S> = {
|
|||
};
|
||||
|
||||
export function getJsonSchema<S extends Schema>(schema: S): ToJsonSchema<Unflatten<ChartResult<S>>> {
|
||||
const unflatten = (str: string, parent: Record<string, any>) => {
|
||||
const keys = str.split('.');
|
||||
const key = keys.shift();
|
||||
const nextKey = keys[0];
|
||||
|
||||
if (key == null) return;
|
||||
|
||||
if (parent.properties[key] == null) {
|
||||
parent.properties[key] = nextKey ? {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: [],
|
||||
} : {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (nextKey) unflatten(keys.join('.'), parent.properties[key] as Record<string, any>);
|
||||
};
|
||||
|
||||
const jsonSchema = {
|
||||
type: 'object',
|
||||
properties: {} as Record<string, unknown>,
|
||||
|
@ -101,10 +124,7 @@ export function getJsonSchema<S extends Schema>(schema: S): ToJsonSchema<Unflatt
|
|||
};
|
||||
|
||||
for (const k in schema) {
|
||||
jsonSchema.properties[k] = {
|
||||
type: 'array',
|
||||
items: { type: 'number' },
|
||||
};
|
||||
unflatten(k, jsonSchema);
|
||||
}
|
||||
|
||||
return jsonSchema as ToJsonSchema<Unflatten<ChartResult<S>>>;
|
||||
|
|
|
@ -38,13 +38,13 @@ export class AbuseUserReportEntityService {
|
|||
targetUserId: report.targetUserId,
|
||||
assigneeId: report.assigneeId,
|
||||
reporter: this.userEntityService.pack(report.reporter ?? report.reporterId, null, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}),
|
||||
targetUser: this.userEntityService.pack(report.targetUser ?? report.targetUserId, null, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}),
|
||||
assignee: report.assigneeId ? this.userEntityService.pack(report.assignee ?? report.assigneeId, null, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}) : null,
|
||||
forwarded: report.forwarded,
|
||||
});
|
||||
|
|
|
@ -37,7 +37,7 @@ export class BlockingEntityService {
|
|||
createdAt: this.idService.parse(blocking.id).date.toISOString(),
|
||||
blockeeId: blocking.blockeeId,
|
||||
blockee: this.userEntityService.pack(blocking.blockeeId, me, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ export class FlashEntityService {
|
|||
createdAt: this.idService.parse(flash.id).date.toISOString(),
|
||||
updatedAt: flash.updatedAt.toISOString(),
|
||||
userId: flash.userId,
|
||||
user: this.userEntityService.pack(flash.user ?? flash.userId, me), // { detail: true } すると無限ループするので注意
|
||||
user: this.userEntityService.pack(flash.user ?? flash.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意
|
||||
title: flash.title,
|
||||
summary: flash.summary,
|
||||
script: flash.script,
|
||||
|
|
|
@ -89,10 +89,10 @@ export class FollowingEntityService {
|
|||
followeeId: following.followeeId,
|
||||
followerId: following.followerId,
|
||||
followee: opts.populateFollowee ? this.userEntityService.pack(following.followee ?? following.followeeId, me, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}) : undefined,
|
||||
follower: opts.populateFollower ? this.userEntityService.pack(following.follower ?? following.followerId, me, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}) : undefined,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export class ModerationLogEntityService {
|
|||
info: log.info,
|
||||
userId: log.userId,
|
||||
user: this.userEntityService.pack(log.user ?? log.userId, null, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ export class MutingEntityService {
|
|||
expiresAt: muting.expiresAt ? muting.expiresAt.toISOString() : null,
|
||||
muteeId: muting.muteeId,
|
||||
mutee: this.userEntityService.pack(muting.muteeId, me, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ export class NoteEntityService implements OnModuleInit {
|
|||
|
||||
return {
|
||||
multiple: poll.multiple,
|
||||
expiresAt: poll.expiresAt,
|
||||
expiresAt: poll.expiresAt?.toISOString() ?? null,
|
||||
choices,
|
||||
};
|
||||
}
|
||||
|
@ -342,9 +342,7 @@ export class NoteEntityService implements OnModuleInit {
|
|||
createdAt: this.idService.parse(note.id).date.toISOString(),
|
||||
updatedAt: note.updatedAt ? note.updatedAt.toISOString() : undefined,
|
||||
userId: note.userId,
|
||||
user: this.userEntityService.pack(note.user ?? note.userId, me, {
|
||||
detail: false,
|
||||
}),
|
||||
user: this.userEntityService.pack(note.user ?? note.userId, me),
|
||||
text: text,
|
||||
cw: note.cw,
|
||||
visibility: note.visibility,
|
||||
|
|
|
@ -62,7 +62,7 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
},
|
||||
hint?: {
|
||||
packedNotes: Map<MiNote['id'], Packed<'Note'>>;
|
||||
packedUsers: Map<MiUser['id'], Packed<'User'>>;
|
||||
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>;
|
||||
},
|
||||
): Promise<Packed<'Notification'>> {
|
||||
const notification = src;
|
||||
|
@ -76,9 +76,7 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
const userIfNeed = 'notifierId' in notification ? (
|
||||
hint?.packedUsers != null
|
||||
? hint.packedUsers.get(notification.notifierId)
|
||||
: this.userEntityService.pack(notification.notifierId, { id: meId }, {
|
||||
detail: false,
|
||||
})
|
||||
: this.userEntityService.pack(notification.notifierId, { id: meId })
|
||||
) : undefined;
|
||||
const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined;
|
||||
|
||||
|
@ -131,9 +129,7 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
const users = userIds.length > 0 ? await this.usersRepository.find({
|
||||
where: { id: In(userIds) },
|
||||
}) : [];
|
||||
const packedUsersArray = await this.userEntityService.packMany(users, { id: meId }, {
|
||||
detail: false,
|
||||
});
|
||||
const packedUsersArray = await this.userEntityService.packMany(users, { id: meId });
|
||||
const packedUsers = new Map(packedUsersArray.map(p => [p.id, p]));
|
||||
|
||||
// 既に解決されたフォローリクエストの通知を除外
|
||||
|
@ -161,7 +157,7 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
},
|
||||
hint?: {
|
||||
packedNotes: Map<MiNote['id'], Packed<'Note'>>;
|
||||
packedUsers: Map<MiUser['id'], Packed<'User'>>;
|
||||
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>;
|
||||
},
|
||||
): Promise<Packed<'Notification'>> {
|
||||
const notification = src;
|
||||
|
@ -175,18 +171,14 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
const userIfNeed = 'notifierId' in notification ? (
|
||||
hint?.packedUsers != null
|
||||
? hint.packedUsers.get(notification.notifierId)
|
||||
: this.userEntityService.pack(notification.notifierId, { id: meId }, {
|
||||
detail: false,
|
||||
})
|
||||
: this.userEntityService.pack(notification.notifierId, { id: meId })
|
||||
) : undefined;
|
||||
|
||||
if (notification.type === 'reaction:grouped') {
|
||||
const reactions = await Promise.all(notification.reactions.map(async reaction => {
|
||||
const user = hint?.packedUsers != null
|
||||
? hint.packedUsers.get(reaction.userId)!
|
||||
: await this.userEntityService.pack(reaction.userId, { id: meId }, {
|
||||
detail: false,
|
||||
});
|
||||
: await this.userEntityService.pack(reaction.userId, { id: meId });
|
||||
return {
|
||||
user,
|
||||
reaction: reaction.reaction,
|
||||
|
@ -206,9 +198,7 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
return packedUser;
|
||||
}
|
||||
|
||||
return this.userEntityService.pack(userId, { id: meId }, {
|
||||
detail: false,
|
||||
});
|
||||
return this.userEntityService.pack(userId, { id: meId });
|
||||
}));
|
||||
return await awaitAll({
|
||||
id: notification.id,
|
||||
|
@ -275,9 +265,7 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
const users = userIds.length > 0 ? await this.usersRepository.find({
|
||||
where: { id: In(userIds) },
|
||||
}) : [];
|
||||
const packedUsersArray = await this.userEntityService.packMany(users, { id: meId }, {
|
||||
detail: false,
|
||||
});
|
||||
const packedUsersArray = await this.userEntityService.packMany(users, { id: meId });
|
||||
const packedUsers = new Map(packedUsersArray.map(p => [p.id, p]));
|
||||
|
||||
// 既に解決されたフォローリクエストの通知を除外
|
||||
|
|
|
@ -90,7 +90,7 @@ export class PageEntityService {
|
|||
createdAt: this.idService.parse(page.id).date.toISOString(),
|
||||
updatedAt: page.updatedAt.toISOString(),
|
||||
userId: page.userId,
|
||||
user: this.userEntityService.pack(page.user ?? page.userId, me), // { detail: true } すると無限ループするので注意
|
||||
user: this.userEntityService.pack(page.user ?? page.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意
|
||||
content: page.content,
|
||||
variables: page.variables,
|
||||
title: page.title,
|
||||
|
|
|
@ -38,7 +38,7 @@ export class RenoteMutingEntityService {
|
|||
createdAt: this.idService.parse(muting.id).date.toISOString(),
|
||||
muteeId: muting.muteeId,
|
||||
mutee: this.userEntityService.pack(muting.muteeId, me, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -30,14 +30,6 @@ import type { NoteEntityService } from './NoteEntityService.js';
|
|||
import type { DriveFileEntityService } from './DriveFileEntityService.js';
|
||||
import type { PageEntityService } from './PageEntityService.js';
|
||||
|
||||
type IsUserDetailed<Detailed extends boolean> = Detailed extends true ? Packed<'UserDetailed'> : Packed<'UserLite'>;
|
||||
type IsMeAndIsUserDetailed<ExpectsMe extends boolean | null, Detailed extends boolean> =
|
||||
Detailed extends true ?
|
||||
ExpectsMe extends true ? Packed<'MeDetailed'> :
|
||||
ExpectsMe extends false ? Packed<'UserDetailedNotMe'> :
|
||||
Packed<'UserDetailed'> :
|
||||
Packed<'UserLite'>;
|
||||
|
||||
const Ajv = _Ajv.default;
|
||||
const ajv = new Ajv();
|
||||
|
||||
|
@ -304,17 +296,17 @@ export class UserEntityService implements OnModuleInit {
|
|||
return `${this.config.url}/users/${userId}`;
|
||||
}
|
||||
|
||||
public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>(
|
||||
public async pack<S extends 'MeDetailed' | 'UserDetailedNotMe' | 'UserDetailed' | 'UserLite' = 'UserLite'>(
|
||||
src: MiUser['id'] | MiUser,
|
||||
me?: { id: MiUser['id']; } | null | undefined,
|
||||
options?: {
|
||||
detail?: D,
|
||||
schema?: S,
|
||||
includeSecrets?: boolean,
|
||||
userProfile?: MiUserProfile,
|
||||
},
|
||||
): Promise<IsMeAndIsUserDetailed<ExpectsMe, D>> {
|
||||
): Promise<Packed<S>> {
|
||||
const opts = Object.assign({
|
||||
detail: false,
|
||||
schema: 'UserLite',
|
||||
includeSecrets: false,
|
||||
}, options);
|
||||
|
||||
|
@ -346,19 +338,20 @@ export class UserEntityService implements OnModuleInit {
|
|||
});
|
||||
}
|
||||
|
||||
const isDetailed = opts.schema !== 'UserLite';
|
||||
const meId = me ? me.id : null;
|
||||
const isMe = meId === user.id;
|
||||
const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false;
|
||||
|
||||
const relation = meId && !isMe && opts.detail ? await this.getRelation(meId, user.id) : null;
|
||||
const pins = opts.detail ? await this.userNotePiningsRepository.createQueryBuilder('pin')
|
||||
const relation = meId && !isMe && isDetailed ? await this.getRelation(meId, user.id) : null;
|
||||
const pins = isDetailed ? await this.userNotePiningsRepository.createQueryBuilder('pin')
|
||||
.where('pin.userId = :userId', { userId: user.id })
|
||||
.innerJoinAndSelect('pin.note', 'note')
|
||||
.orderBy('pin.id', 'DESC')
|
||||
.getMany() : [];
|
||||
const profile = opts.detail ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null;
|
||||
const profile = isDetailed ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null;
|
||||
|
||||
const mastoapi = !opts.detail ? opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id }) : null;
|
||||
const mastoapi = !isDetailed ? opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id }) : null;
|
||||
|
||||
const followingCount = profile == null ? null :
|
||||
(profile.followingVisibility === 'public') || isMe ? user.followingCount :
|
||||
|
@ -370,17 +363,16 @@ export class UserEntityService implements OnModuleInit {
|
|||
(profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
|
||||
null;
|
||||
|
||||
const isModerator = isMe && opts.detail ? this.roleService.isModerator(user) : null;
|
||||
const isAdmin = isMe && opts.detail ? this.roleService.isAdministrator(user) : null;
|
||||
const unreadAnnouncements = isMe && opts.detail ?
|
||||
const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : null;
|
||||
const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : null;
|
||||
const unreadAnnouncements = isMe && isDetailed ?
|
||||
(await this.announcementService.getUnreadAnnouncements(user)).map((announcement) => ({
|
||||
createdAt: this.idService.parse(announcement.id).date.toISOString(),
|
||||
...announcement,
|
||||
})) : null;
|
||||
|
||||
const checkHost = user.host == null ? this.config.host : user.host;
|
||||
|
||||
const notificationsInfo = isMe && opts.detail ? await this.getNotificationsInfo(user.id) : null;
|
||||
const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null;
|
||||
|
||||
const packed = {
|
||||
id: user.id,
|
||||
|
@ -425,7 +417,7 @@ export class UserEntityService implements OnModuleInit {
|
|||
displayOrder: r.displayOrder,
|
||||
}))) : undefined,
|
||||
|
||||
...(opts.detail ? {
|
||||
...(isDetailed ? {
|
||||
url: profile!.url,
|
||||
uri: user.uri,
|
||||
movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null,
|
||||
|
@ -453,7 +445,7 @@ export class UserEntityService implements OnModuleInit {
|
|||
}),
|
||||
pinnedPageId: profile!.pinnedPageId,
|
||||
pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null,
|
||||
publicReactions: profile!.publicReactions,
|
||||
publicReactions: this.isLocalUser(user) ? profile!.publicReactions : false, // https://github.com/misskey-dev/misskey/issues/12964
|
||||
followersVisibility: profile!.followersVisibility,
|
||||
followingVisibility: profile!.followingVisibility,
|
||||
twoFactorEnabled: profile!.twoFactorEnabled,
|
||||
|
@ -480,7 +472,7 @@ export class UserEntityService implements OnModuleInit {
|
|||
moderationNote: iAmModerator ? (profile!.moderationNote ?? '') : undefined,
|
||||
} : {}),
|
||||
|
||||
...(opts.detail && isMe ? {
|
||||
...(isDetailed && isMe ? {
|
||||
avatarId: user.avatarId,
|
||||
bannerId: user.bannerId,
|
||||
backgroundId: user.backgroundId,
|
||||
|
@ -554,19 +546,19 @@ export class UserEntityService implements OnModuleInit {
|
|||
notify: relation.following?.notify ?? 'none',
|
||||
withReplies: relation.following?.withReplies ?? false,
|
||||
} : {}),
|
||||
} as Promiseable<Packed<'User'>> as Promiseable<IsMeAndIsUserDetailed<ExpectsMe, D>>;
|
||||
} as Promiseable<Packed<S>>;
|
||||
|
||||
return await awaitAll(packed);
|
||||
}
|
||||
|
||||
public packMany<D extends boolean = false>(
|
||||
public packMany<S extends 'MeDetailed' | 'UserDetailedNotMe' | 'UserDetailed' | 'UserLite' = 'UserLite'>(
|
||||
users: (MiUser['id'] | MiUser)[],
|
||||
me?: { id: MiUser['id'] } | null | undefined,
|
||||
options?: {
|
||||
detail?: D,
|
||||
schema?: S,
|
||||
includeSecrets?: boolean,
|
||||
},
|
||||
): Promise<IsUserDetailed<D>[]> {
|
||||
): Promise<Packed<S>[]> {
|
||||
return Promise.all(users.map(u => this.pack(u, me, options)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// structredCloneが遅いため
|
||||
// SEE: http://var.blog.jp/archives/86038606.html
|
||||
|
||||
type Cloneable = string | number | boolean | null | { [key: string]: Cloneable } | Cloneable[];
|
||||
type Cloneable = string | number | boolean | null | undefined | { [key: string]: Cloneable } | Cloneable[];
|
||||
|
||||
export function deepClone<T extends Cloneable>(x: T): T {
|
||||
if (typeof x === 'object') {
|
||||
|
@ -14,7 +14,7 @@ export function deepClone<T extends Cloneable>(x: T): T {
|
|||
if (Array.isArray(x)) return x.map(deepClone) as T;
|
||||
const obj = {} as Record<string, Cloneable>;
|
||||
for (const [k, v] of Object.entries(x)) {
|
||||
obj[k] = deepClone(v);
|
||||
obj[k] = v === undefined ? undefined : deepClone(v);
|
||||
}
|
||||
return obj as T;
|
||||
} else {
|
||||
|
|
|
@ -25,7 +25,7 @@ import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
|
|||
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
|
||||
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
|
||||
import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js';
|
||||
import { packedPageSchema } from '@/models/json-schema/page.js';
|
||||
import { packedPageSchema, packedPageBlockSchema } from '@/models/json-schema/page.js';
|
||||
import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js';
|
||||
import { packedChannelSchema } from '@/models/json-schema/channel.js';
|
||||
import { packedAntennaSchema } from '@/models/json-schema/antenna.js';
|
||||
|
@ -37,7 +37,7 @@ import { packedEmojiDetailedSchema, packedEmojiSimpleSchema } from '@/models/jso
|
|||
import { packedFlashSchema } from '@/models/json-schema/flash.js';
|
||||
import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js';
|
||||
import { packedSigninSchema } from '@/models/json-schema/signin.js';
|
||||
import { packedRoleLiteSchema, packedRoleSchema } from '@/models/json-schema/role.js';
|
||||
import { packedRoleLiteSchema, packedRoleSchema, packedRolePoliciesSchema } from '@/models/json-schema/role.js';
|
||||
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
||||
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
|
||||
|
||||
|
@ -67,6 +67,7 @@ export const refs = {
|
|||
Hashtag: packedHashtagSchema,
|
||||
InviteCode: packedInviteCodeSchema,
|
||||
Page: packedPageSchema,
|
||||
PageBlock: packedPageBlockSchema,
|
||||
Channel: packedChannelSchema,
|
||||
QueueCount: packedQueueCountSchema,
|
||||
Antenna: packedAntennaSchema,
|
||||
|
@ -79,12 +80,16 @@ export const refs = {
|
|||
Signin: packedSigninSchema,
|
||||
RoleLite: packedRoleLiteSchema,
|
||||
Role: packedRoleSchema,
|
||||
RolePolicies: packedRolePoliciesSchema,
|
||||
ReversiGameLite: packedReversiGameLiteSchema,
|
||||
ReversiGameDetailed: packedReversiGameDetailedSchema,
|
||||
};
|
||||
|
||||
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
|
||||
|
||||
export type KeyOf<x extends keyof typeof refs> = PropertiesToUnion<typeof refs[x]>;
|
||||
type PropertiesToUnion<p extends Schema> = p['properties'] extends NonNullable<Obj> ? keyof p['properties'] : never;
|
||||
|
||||
type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any';
|
||||
type StringDefToType<T extends TypeStringef> =
|
||||
T extends 'null' ? null :
|
||||
|
@ -114,6 +119,7 @@ export interface Schema extends OfSchema {
|
|||
readonly example?: any;
|
||||
readonly format?: string;
|
||||
readonly ref?: keyof typeof refs;
|
||||
readonly selfRef?: boolean;
|
||||
readonly enum?: ReadonlyArray<string | null>;
|
||||
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
|
||||
readonly maxLength?: number;
|
||||
|
|
|
@ -38,7 +38,7 @@ export class MiAnnouncement {
|
|||
length: 256, nullable: false,
|
||||
default: 'info',
|
||||
})
|
||||
public icon: string;
|
||||
public icon: 'info' | 'warning' | 'error' | 'success';
|
||||
|
||||
// normal ... お知らせページ掲載
|
||||
// banner ... お知らせページ掲載 + バナー表示
|
||||
|
@ -47,7 +47,7 @@ export class MiAnnouncement {
|
|||
length: 256, nullable: false,
|
||||
default: 'normal',
|
||||
})
|
||||
public display: string;
|
||||
public display: 'normal' | 'banner' | 'dialog';
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
|
|
|
@ -37,10 +37,12 @@ export const packedAnnouncementSchema = {
|
|||
icon: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['info', 'warning', 'error', 'success'],
|
||||
},
|
||||
display: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['dialog', 'normal', 'banner'],
|
||||
},
|
||||
needConfirmationToRead: {
|
||||
type: 'boolean',
|
||||
|
|
|
@ -25,7 +25,7 @@ export const packedBlockingSchema = {
|
|||
blockee: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'UserDetailed',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -30,12 +30,12 @@ export const packedFollowingSchema = {
|
|||
followee: {
|
||||
type: 'object',
|
||||
optional: true, nullable: false,
|
||||
ref: 'UserDetailed',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
follower: {
|
||||
type: 'object',
|
||||
optional: true, nullable: false,
|
||||
ref: 'UserDetailed',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -30,7 +30,7 @@ export const packedMutingSchema = {
|
|||
mutee: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'UserDetailed',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -69,6 +69,7 @@ export const packedNoteSchema = {
|
|||
visibility: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['public', 'home', 'followers', 'specified'],
|
||||
},
|
||||
mentions: {
|
||||
type: 'array',
|
||||
|
@ -117,6 +118,48 @@ export const packedNoteSchema = {
|
|||
poll: {
|
||||
type: 'object',
|
||||
optional: true, nullable: true,
|
||||
properties: {
|
||||
expiresAt: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
format: 'date-time',
|
||||
},
|
||||
multiple: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
choices: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
isVoted: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
text: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
votes: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
emojis: {
|
||||
type: 'object',
|
||||
optional: true, nullable: false,
|
||||
additionalProperties: {
|
||||
anyOf: [{
|
||||
type: 'string',
|
||||
}],
|
||||
},
|
||||
},
|
||||
channelId: {
|
||||
type: 'string',
|
||||
|
@ -162,9 +205,23 @@ export const packedNoteSchema = {
|
|||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
reactionEmojis: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
additionalProperties: {
|
||||
anyOf: [{
|
||||
type: 'string',
|
||||
}],
|
||||
},
|
||||
},
|
||||
reactions: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
additionalProperties: {
|
||||
anyOf: [{
|
||||
type: 'number',
|
||||
}],
|
||||
},
|
||||
},
|
||||
renoteCount: {
|
||||
type: 'number',
|
||||
|
@ -196,7 +253,7 @@ export const packedNoteSchema = {
|
|||
},
|
||||
|
||||
myReaction: {
|
||||
type: 'object',
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { notificationTypes } from '@/types.js';
|
||||
|
||||
export const packedNotificationSchema = {
|
||||
const baseSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
|
@ -23,68 +23,368 @@ export const packedNotificationSchema = {
|
|||
optional: false, nullable: false,
|
||||
enum: [...notificationTypes, 'reaction:grouped', 'renote:grouped'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
reaction: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
achievement: {
|
||||
type: 'string',
|
||||
optional: true, nullable: false,
|
||||
},
|
||||
body: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
header: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
icon: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
reactions: {
|
||||
type: 'array',
|
||||
optional: true, nullable: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
reaction: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
required: ['user', 'reaction'],
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const packedNotificationSchema = {
|
||||
type: 'object',
|
||||
oneOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['note'],
|
||||
},
|
||||
},
|
||||
users: {
|
||||
type: 'array',
|
||||
optional: true, nullable: true,
|
||||
items: {
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['mention'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['reply'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['renote'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['quote'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['reaction'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
reaction: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['pollEnded'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['follow'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['receiveFollowRequest'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['followRequestAccepted'],
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['roleAssigned'],
|
||||
},
|
||||
role: {
|
||||
type: 'object',
|
||||
ref: 'Role',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['achievementEarned'],
|
||||
},
|
||||
achievement: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['app'],
|
||||
},
|
||||
body: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
header: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
icon: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['reaction:grouped'],
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
reactions: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
reaction: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
required: ['user', 'reaction'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['renote:grouped'],
|
||||
},
|
||||
note: {
|
||||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
users: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
ref: 'UserLite',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['test'],
|
||||
},
|
||||
},
|
||||
}],
|
||||
} as const;
|
||||
|
|
|
@ -3,6 +3,108 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
const blockBaseSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
const textBlockSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...blockBaseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['text'],
|
||||
},
|
||||
text: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
const sectionBlockSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...blockBaseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['section'],
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
children: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'PageBlock',
|
||||
selfRef: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
const imageBlockSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...blockBaseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['image'],
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
const noteBlockSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...blockBaseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['note'],
|
||||
},
|
||||
detailed: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
note: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const packedPageBlockSchema = {
|
||||
type: 'object',
|
||||
oneOf: [
|
||||
textBlockSchema,
|
||||
sectionBlockSchema,
|
||||
imageBlockSchema,
|
||||
noteBlockSchema,
|
||||
],
|
||||
} as const;
|
||||
|
||||
export const packedPageSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
@ -38,6 +140,7 @@ export const packedPageSchema = {
|
|||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'PageBlock',
|
||||
},
|
||||
},
|
||||
variables: {
|
||||
|
|
|
@ -25,7 +25,7 @@ export const packedRenoteMutingSchema = {
|
|||
mutee: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'UserDetailed',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -1,26 +1,103 @@
|
|||
const rolePolicyValue = {
|
||||
export const packedRolePoliciesSchema = {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
value: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
],
|
||||
gtlAvailable: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
priority: {
|
||||
ltlAvailable: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canPublicNote: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canInvite: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
inviteLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
useDefault: {
|
||||
inviteLimitCycle: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
inviteExpirationTime: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canManageCustomEmojis: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canManageAvatarDecorations: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canSearchNotes: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canUseTranslator: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canHideAds: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
driveCapacityMb: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
alwaysMarkNsfw: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
pinLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
antennaLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
wordMuteLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
webhookLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
clipLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
noteEachClipsLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userListLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userEachUserListsLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
rateLimitFactor: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
avatarDecorationLimit: {
|
||||
type: 'integer',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
@ -121,31 +198,28 @@ export const packedRoleSchema = {
|
|||
policies: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
pinLimit: rolePolicyValue,
|
||||
canInvite: rolePolicyValue,
|
||||
clipLimit: rolePolicyValue,
|
||||
canHideAds: rolePolicyValue,
|
||||
inviteLimit: rolePolicyValue,
|
||||
antennaLimit: rolePolicyValue,
|
||||
gtlAvailable: rolePolicyValue,
|
||||
ltlAvailable: rolePolicyValue,
|
||||
webhookLimit: rolePolicyValue,
|
||||
canPublicNote: rolePolicyValue,
|
||||
userListLimit: rolePolicyValue,
|
||||
wordMuteLimit: rolePolicyValue,
|
||||
alwaysMarkNsfw: rolePolicyValue,
|
||||
canSearchNotes: rolePolicyValue,
|
||||
driveCapacityMb: rolePolicyValue,
|
||||
rateLimitFactor: rolePolicyValue,
|
||||
inviteLimitCycle: rolePolicyValue,
|
||||
noteEachClipsLimit: rolePolicyValue,
|
||||
inviteExpirationTime: rolePolicyValue,
|
||||
canManageCustomEmojis: rolePolicyValue,
|
||||
userEachUserListsLimit: rolePolicyValue,
|
||||
canManageAvatarDecorations: rolePolicyValue,
|
||||
canUseTranslator: rolePolicyValue,
|
||||
avatarDecorationLimit: rolePolicyValue,
|
||||
additionalProperties: {
|
||||
anyOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
value: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'integer',
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
},
|
||||
],
|
||||
},
|
||||
priority: {
|
||||
type: 'integer',
|
||||
},
|
||||
useDefault: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
usersCount: {
|
||||
|
|
|
@ -628,104 +628,7 @@ export const packedMeDetailedOnlySchema = {
|
|||
policies: {
|
||||
type: 'object',
|
||||
nullable: false, optional: false,
|
||||
properties: {
|
||||
gtlAvailable: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
ltlAvailable: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
canPublicNote: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
canInvite: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
inviteLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
inviteLimitCycle: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
inviteExpirationTime: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
canManageCustomEmojis: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
canManageAvatarDecorations: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
canSearchNotes: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
canUseTranslator: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
canHideAds: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
driveCapacityMb: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
alwaysMarkNsfw: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
pinLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
antennaLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
wordMuteLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
webhookLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
clipLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
noteEachClipsLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
userListLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
userEachUserListsLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
rateLimitFactor: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
avatarDecorationLimit: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
},
|
||||
ref: 'RolePolicies',
|
||||
},
|
||||
//#region secrets
|
||||
email: {
|
||||
|
@ -820,13 +723,5 @@ export const packedUserSchema = {
|
|||
type: 'object',
|
||||
ref: 'UserDetailed',
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
ref: 'MeDetailed',
|
||||
},
|
||||
],
|
||||
} as const;
|
||||
|
|
|
@ -295,9 +295,9 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
}, {
|
||||
...baseQueueOptions(this.config, QUEUE.RELATIONSHIP),
|
||||
autorun: false,
|
||||
concurrency: this.config.relashionshipJobConcurrency ?? 16,
|
||||
concurrency: this.config.relationshipJobConcurrency ?? 16,
|
||||
limiter: {
|
||||
max: this.config.relashionshipJobPerSec ?? 64,
|
||||
max: this.config.relationshipJobPerSec ?? 64,
|
||||
duration: 1000,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -206,7 +206,7 @@ export class ServerService implements OnApplicationShutdown {
|
|||
});
|
||||
|
||||
this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
}));
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ export class ApiServerService {
|
|||
return {
|
||||
ok: true,
|
||||
token: token.token,
|
||||
user: await this.userEntityService.pack(token.userId, null, { detail: true }),
|
||||
user: await this.userEntityService.pack(token.userId, null, { schema: 'UserDetailedNotMe' }),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
|
|
|
@ -260,7 +260,7 @@ export class SignupApiService {
|
|||
});
|
||||
|
||||
const res = await this.userEntityService.pack(account, account, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
});
|
||||
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
*/
|
||||
|
||||
import { permissions } from 'misskey-js';
|
||||
import type { Schema } from '@/misc/json-schema.js';
|
||||
import { RolePolicies } from '@/core/RoleService.js';
|
||||
import type { KeyOf, Schema } from '@/misc/json-schema.js';
|
||||
|
||||
import * as ep___admin_meta from './endpoints/admin/meta.js';
|
||||
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
|
||||
|
@ -802,7 +801,7 @@ interface IEndpointMetaBase {
|
|||
*/
|
||||
readonly requireAdmin?: boolean;
|
||||
|
||||
readonly requireRolePolicy?: keyof RolePolicies;
|
||||
readonly requireRolePolicy?: KeyOf<'RolePolicies'>;
|
||||
|
||||
/**
|
||||
* 引っ越し済みのユーザーによるリクエストを禁止するか
|
||||
|
|
|
@ -62,17 +62,17 @@ export const meta = {
|
|||
reporter: {
|
||||
type: 'object',
|
||||
nullable: false, optional: false,
|
||||
ref: 'User',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
targetUser: {
|
||||
type: 'object',
|
||||
nullable: false, optional: false,
|
||||
ref: 'User',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
assignee: {
|
||||
type: 'object',
|
||||
nullable: true, optional: true,
|
||||
ref: 'User',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -11,6 +11,7 @@ import { SignupService } from '@/core/SignupService.js';
|
|||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { localUsernameSchema, passwordSchema } from '@/models/User.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { Packed } from '@/misc/json-schema.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
@ -18,7 +19,7 @@ export const meta = {
|
|||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'User',
|
||||
ref: 'MeDetailed',
|
||||
properties: {
|
||||
token: {
|
||||
type: 'string',
|
||||
|
@ -60,11 +61,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
});
|
||||
|
||||
const res = await this.userEntityService.pack(account, account, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
});
|
||||
}) as Packed<'MeDetailed'> & { token: string };
|
||||
|
||||
(res as any).token = secret;
|
||||
res.token = secret;
|
||||
|
||||
return res;
|
||||
});
|
||||
|
|
|
@ -27,7 +27,7 @@ export const meta = {
|
|||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'User',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
@ -58,7 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
}
|
||||
|
||||
const res = await this.userEntityService.pack(profile.user!, null, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
});
|
||||
|
||||
return res;
|
||||
|
|
|
@ -40,7 +40,7 @@ export const meta = {
|
|||
},
|
||||
required: ['id', 'createdAt', 'user'],
|
||||
},
|
||||
}
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@ -92,7 +92,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
return await Promise.all(assigns.map(async assign => ({
|
||||
id: assign.id,
|
||||
createdAt: this.idService.parse(assign.id).date.toISOString(),
|
||||
user: await this.userEntityService.pack(assign.user!, me, { detail: true }),
|
||||
user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
|
||||
expiresAt: assign.expiresAt?.toISOString() ?? null,
|
||||
})));
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@ export const meta = {
|
|||
user: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'UserDetailed',
|
||||
ref: 'UserDetailedNotMe',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -115,7 +115,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
const users = await query.getMany();
|
||||
|
||||
return await this.userEntityService.packMany(users, me, { detail: true });
|
||||
return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
if (user != null) {
|
||||
return {
|
||||
type: 'User',
|
||||
object: await this.userEntityService.pack(user, me, { detail: true }),
|
||||
object: await this.userEntityService.pack(user, me, { schema: 'UserDetailedNotMe' }),
|
||||
};
|
||||
} else if (note != null) {
|
||||
try {
|
||||
|
|
|
@ -112,7 +112,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
return {
|
||||
accessToken: accessToken.token,
|
||||
user: await this.userEntityService.pack(session.userId, null, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
|
|
@ -102,7 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
await this.userBlockingService.block(blocker, blockee);
|
||||
|
||||
return await this.userEntityService.pack(blockee.id, blocker, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
await this.userBlockingService.unblock(blocker, blockee);
|
||||
|
||||
return await this.userEntityService.pack(blockee.id, blocker, {
|
||||
detail: true,
|
||||
schema: 'UserDetailedNotMe',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
relations: ['user'],
|
||||
});
|
||||
|
||||
const users = await this.userEntityService.packMany(records.map(r => r.user!), null, { detail: false });
|
||||
const users = await this.userEntityService.packMany(records.map(r => r.user!), null);
|
||||
|
||||
return records.map(r => ({
|
||||
id: r.id,
|
||||
|
|
|
@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
.limit(ps.limit)
|
||||
.getMany();
|
||||
|
||||
return await this.userEntityService.packMany(users, me, { detail: true });
|
||||
return await this.userEntityService.packMany(users, me, { schema: 'UserDetailedNotMe' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
const users = await query.limit(ps.limit).getMany();
|
||||
|
||||
return await this.userEntityService.packMany(users, me, { detail: true });
|
||||
return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
userProfile.loggedInDates = [...userProfile.loggedInDates, today];
|
||||
}
|
||||
|
||||
return await this.userEntityService.pack<true, true>(userProfile.user!, userProfile.user!, {
|
||||
detail: true,
|
||||
return await this.userEntityService.pack(userProfile.user!, userProfile.user!, {
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: isSecure,
|
||||
userProfile,
|
||||
});
|
||||
|
|
|
@ -64,7 +64,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
// Publish meUpdated event
|
||||
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
}));
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
|
||||
// Publish meUpdated event
|
||||
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
}));
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
// Publish meUpdated event
|
||||
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -99,7 +99,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
// Publish meUpdated event
|
||||
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
}));
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
// Publish meUpdated event
|
||||
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -69,7 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
// Publish meUpdated event
|
||||
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
}));
|
||||
|
||||
|
|
|
@ -66,8 +66,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
throw err;
|
||||
});
|
||||
|
||||
return await this.userEntityService.pack<true, true>(me.id, me, {
|
||||
detail: true,
|
||||
return await this.userEntityService.pack(me.id, me, {
|
||||
schema: 'MeDetailed',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -51,8 +51,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
throw err;
|
||||
});
|
||||
|
||||
return await this.userEntityService.pack<true, true>(me.id, me, {
|
||||
detail: true,
|
||||
return await this.userEntityService.pack(me.id, me, {
|
||||
schema: 'MeDetailed',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ export const meta = {
|
|||
|
||||
res: {
|
||||
type: 'object',
|
||||
ref: 'UserDetailed',
|
||||
ref: 'MeDetailed',
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
@ -107,7 +107,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
});
|
||||
|
||||
const iObj = await this.userEntityService.pack(me.id, me, {
|
||||
detail: true,
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: true,
|
||||
});
|
||||
|
||||
|
|
|
@ -478,8 +478,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
verifiedLinks: [],
|
||||
});
|
||||
|
||||
const iObj = await this.userEntityService.pack<true, true>(user.id, user, {
|
||||
detail: true,
|
||||
const iObj = await this.userEntityService.pack(user.id, user, {
|
||||
schema: 'MeDetailed',
|
||||
includeSecrets: isSecure,
|
||||
});
|
||||
|
||||
|
|
|
@ -314,6 +314,11 @@ export const meta = {
|
|||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
policies: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'RolePolicies',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -55,7 +55,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
var: ps.var,
|
||||
userId: me.id,
|
||||
user: await this.userEntityService.pack(me.id, { id: page.userId }, {
|
||||
detail: true,
|
||||
schema: 'UserDetailed',
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
|
|
@ -52,7 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
host: acct.host ?? IsNull(),
|
||||
})));
|
||||
|
||||
return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { detail: true });
|
||||
return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { schema: 'UserDetailed' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,32 @@ export const meta = {
|
|||
requireCredential: false,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
users: {
|
||||
type: 'number',
|
||||
},
|
||||
data: {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
anyOf: [{
|
||||
type: 'number',
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: [
|
||||
'createdAt',
|
||||
'users',
|
||||
'data',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
allowGet: true,
|
||||
|
|
|
@ -33,11 +33,11 @@ export const meta = {
|
|||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id'
|
||||
format: 'misskey:id',
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'User'
|
||||
ref: 'UserDetailed',
|
||||
},
|
||||
},
|
||||
required: ['id', 'user'],
|
||||
|
@ -94,7 +94,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
return await Promise.all(assigns.map(async assign => ({
|
||||
id: assign.id,
|
||||
user: await this.userEntityService.pack(assign.user!, me, { detail: true }),
|
||||
user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
|
||||
})));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
const users = await query.getMany();
|
||||
|
||||
return await this.userEntityService.packMany(users, me, { detail: true });
|
||||
return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
// Make replies object (includes weights)
|
||||
const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({
|
||||
user: await this.userEntityService.pack(user, me, { detail: true }),
|
||||
user: await this.userEntityService.pack(user, me, { schema: 'UserDetailed' }),
|
||||
weight: repliedUsers[user] / peak,
|
||||
})));
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ export const meta = {
|
|||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'User',
|
||||
ref: 'UserLite',
|
||||
},
|
||||
withReplies: {
|
||||
type: 'boolean',
|
||||
|
|
|
@ -9,6 +9,9 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
|||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
@ -34,6 +37,11 @@ export const meta = {
|
|||
code: 'REACTIONS_NOT_PUBLIC',
|
||||
id: '673a7dd2-6924-1093-e0c0-e68456ceae5c',
|
||||
},
|
||||
isRemoteUser: {
|
||||
message: 'Currently unavailable to display reactions of remote users. See https://github.com/misskey-dev/misskey/issues/12964',
|
||||
code: 'IS_REMOTE_USER',
|
||||
id: '6b95fa98-8cf9-2350-e284-f0ffdb54a805',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
@ -59,14 +67,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
@Inject(DI.noteReactionsRepository)
|
||||
private noteReactionsRepository: NoteReactionsRepository,
|
||||
|
||||
private cacheService: CacheService,
|
||||
private userEntityService: UserEntityService,
|
||||
private noteReactionEntityService: NoteReactionEntityService,
|
||||
private queryService: QueryService,
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
|
||||
const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users
|
||||
if (!iAmModerator) {
|
||||
const user = await this.cacheService.findUserById(ps.userId);
|
||||
if (this.userEntityService.isRemoteUser(user)) {
|
||||
throw new ApiError(meta.errors.isRemoteUser);
|
||||
}
|
||||
|
||||
if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
|
||||
throw new ApiError(meta.errors.reactionsNotPublic);
|
||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
|
||||
if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
|
||||
throw new ApiError(meta.errors.reactionsNotPublic);
|
||||
}
|
||||
}
|
||||
|
||||
const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'),
|
||||
|
|
|
@ -76,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
const users = await query.limit(ps.limit).offset(ps.offset).getMany();
|
||||
|
||||
return await this.userEntityService.packMany(users, me, { detail: true });
|
||||
return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
.getMany();
|
||||
}
|
||||
|
||||
return await this.userEntityService.packMany(users, me, { detail: !!ps.detail });
|
||||
return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
}
|
||||
}
|
||||
|
||||
return await this.userEntityService.packMany(users, me, { detail: ps.detail });
|
||||
return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
}
|
||||
|
||||
return await Promise.all(_users.map(u => this.userEntityService.pack(u, me, {
|
||||
detail: true,
|
||||
schema: 'UserDetailed',
|
||||
})));
|
||||
} else {
|
||||
// Lookup user
|
||||
|
@ -146,7 +146,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
}
|
||||
|
||||
return await this.userEntityService.pack(user, me, {
|
||||
detail: true,
|
||||
schema: 'UserDetailed',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
import type { Config } from '@/config.js';
|
||||
import endpoints, { IEndpoint } from '../endpoints.js';
|
||||
import { errors as basicErrors } from './errors.js';
|
||||
import { schemas, convertSchemaToOpenApiSchema } from './schemas.js';
|
||||
import { getSchemas, convertSchemaToOpenApiSchema } from './schemas.js';
|
||||
|
||||
export function genOpenapiSpec(config: Config) {
|
||||
export function genOpenapiSpec(config: Config, includeSelfRef = false) {
|
||||
const spec = {
|
||||
openapi: '3.1.0',
|
||||
|
||||
|
@ -30,7 +30,7 @@ export function genOpenapiSpec(config: Config) {
|
|||
paths: {} as any,
|
||||
|
||||
components: {
|
||||
schemas: schemas,
|
||||
schemas: getSchemas(includeSelfRef),
|
||||
|
||||
securitySchemes: {
|
||||
bearerAuth: {
|
||||
|
@ -56,7 +56,7 @@ export function genOpenapiSpec(config: Config) {
|
|||
}
|
||||
}
|
||||
|
||||
const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res') : {};
|
||||
const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res', includeSelfRef) : {};
|
||||
|
||||
let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n';
|
||||
|
||||
|
@ -71,7 +71,7 @@ export function genOpenapiSpec(config: Config) {
|
|||
}
|
||||
|
||||
const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json';
|
||||
const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param') };
|
||||
const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param', false) };
|
||||
|
||||
if (endpoint.meta.requireFile) {
|
||||
schema.properties = {
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
import type { Schema } from '@/misc/json-schema.js';
|
||||
import { refs } from '@/misc/json-schema.js';
|
||||
|
||||
export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res') {
|
||||
export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res', includeSelfRef: boolean): any {
|
||||
// optional, nullable, refはスキーマ定義に含まれないので分離しておく
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { optional, nullable, ref, ...res }: any = schema;
|
||||
const { optional, nullable, ref, selfRef, ...res }: any = schema;
|
||||
|
||||
if (schema.type === 'object' && schema.properties) {
|
||||
if (type === 'res') {
|
||||
|
@ -21,20 +21,20 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
|
|||
}
|
||||
|
||||
for (const k of Object.keys(schema.properties)) {
|
||||
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type);
|
||||
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type, includeSelfRef);
|
||||
}
|
||||
}
|
||||
|
||||
if (schema.type === 'array' && schema.items) {
|
||||
res.items = convertSchemaToOpenApiSchema(schema.items, type);
|
||||
res.items = convertSchemaToOpenApiSchema(schema.items, type, includeSelfRef);
|
||||
}
|
||||
|
||||
for (const o of ['anyOf', 'oneOf', 'allOf'] as const) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type));
|
||||
if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type, includeSelfRef));
|
||||
}
|
||||
|
||||
if (type === 'res' && schema.ref) {
|
||||
if (type === 'res' && schema.ref && (!schema.selfRef || includeSelfRef)) {
|
||||
const $ref = `#/components/schemas/${schema.ref}`;
|
||||
if (schema.nullable || schema.optional) {
|
||||
res.allOf = [{ $ref }];
|
||||
|
@ -54,35 +54,37 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
|
|||
return res;
|
||||
}
|
||||
|
||||
export const schemas = {
|
||||
Error: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'object',
|
||||
description: 'An error object.',
|
||||
properties: {
|
||||
code: {
|
||||
type: 'string',
|
||||
description: 'An error code. Unique within the endpoint.',
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
description: 'An error message.',
|
||||
},
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'uuid',
|
||||
description: 'An error ID. This ID is static.',
|
||||
export function getSchemas(includeSelfRef: boolean) {
|
||||
return {
|
||||
Error: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'object',
|
||||
description: 'An error object.',
|
||||
properties: {
|
||||
code: {
|
||||
type: 'string',
|
||||
description: 'An error code. Unique within the endpoint.',
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
description: 'An error message.',
|
||||
},
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'uuid',
|
||||
description: 'An error ID. This ID is static.',
|
||||
},
|
||||
},
|
||||
required: ['code', 'id', 'message'],
|
||||
},
|
||||
required: ['code', 'id', 'message'],
|
||||
},
|
||||
required: ['error'],
|
||||
},
|
||||
required: ['error'],
|
||||
},
|
||||
|
||||
...Object.fromEntries(
|
||||
Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res')]),
|
||||
),
|
||||
};
|
||||
...Object.fromEntries(
|
||||
Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res', includeSelfRef)]),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue