From 4d021f315fb6c36feabdb8a43592cd27757f8af4 Mon Sep 17 00:00:00 2001 From: tamaina Date: Tue, 20 Jun 2023 07:38:15 +0000 Subject: [PATCH] wip --- .../api/endpoints/federation/followers.ts | 32 +-- .../api/endpoints/federation/following.ts | 32 +-- .../api/endpoints/federation/instances.ts | 40 +-- .../api/endpoints/federation/show-instance.ts | 28 +-- .../server/api/endpoints/federation/stats.ts | 5 +- .../federation/update-remote-user.ts | 19 +- .../server/api/endpoints/federation/users.ts | 32 +-- packages/misskey-js/src/endpoints.ts | 227 +++++++++++++++++- 8 files changed, 238 insertions(+), 177 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/federation/followers.ts b/packages/backend/src/server/api/endpoints/federation/followers.ts index be1d6c8e58..51a60e1dce 100644 --- a/packages/backend/src/server/api/endpoints/federation/followers.ts +++ b/packages/backend/src/server/api/endpoints/federation/followers.ts @@ -5,36 +5,10 @@ import { QueryService } from '@/core/QueryService.js'; import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js'; import { DI } from '@/di-symbols.js'; -export const meta = { - tags: ['federation'], - - requireCredential: false, - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - ref: 'Following', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - host: { type: 'string' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - }, - required: ['host'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'federation/followers'> { + name = 'federation/followers' as const; constructor( @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, @@ -42,7 +16,7 @@ export default class extends Endpoint { private followingEntityService: FollowingEntityService, private queryService: QueryService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId) .andWhere('following.followeeHost = :host', { host: ps.host }); diff --git a/packages/backend/src/server/api/endpoints/federation/following.ts b/packages/backend/src/server/api/endpoints/federation/following.ts index 74656ce863..01dea5b42e 100644 --- a/packages/backend/src/server/api/endpoints/federation/following.ts +++ b/packages/backend/src/server/api/endpoints/federation/following.ts @@ -5,36 +5,10 @@ import { QueryService } from '@/core/QueryService.js'; import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js'; import { DI } from '@/di-symbols.js'; -export const meta = { - tags: ['federation'], - - requireCredential: false, - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - ref: 'Following', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - host: { type: 'string' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - }, - required: ['host'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'federation/followings'> { + name = 'federation/followings' as const; constructor( @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, @@ -42,7 +16,7 @@ export default class extends Endpoint { private followingEntityService: FollowingEntityService, private queryService: QueryService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId) .andWhere('following.followerHost = :host', { host: ps.host }); diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 061c6eb5be..85901262f7 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -6,44 +6,10 @@ import { MetaService } from '@/core/MetaService.js'; import { DI } from '@/di-symbols.js'; import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; -export const meta = { - tags: ['federation'], - - requireCredential: false, - allowGet: true, - cacheSec: 3600, - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - ref: 'FederationInstance', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - host: { type: 'string', nullable: true, description: 'Omit or use `null` to not filter by host.' }, - blocked: { type: 'boolean', nullable: true }, - notResponding: { type: 'boolean', nullable: true }, - suspended: { type: 'boolean', nullable: true }, - federating: { type: 'boolean', nullable: true }, - subscribing: { type: 'boolean', nullable: true }, - publishing: { type: 'boolean', nullable: true }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, - offset: { type: 'integer', default: 0 }, - sort: { type: 'string' }, - }, - required: [], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'federation/instances'> { + name = 'federation/instances' as const; constructor( @Inject(DI.instancesRepository) private instancesRepository: InstancesRepository, @@ -51,7 +17,7 @@ export default class extends Endpoint { private instanceEntityService: InstanceEntityService, private metaService: MetaService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const query = this.instancesRepository.createQueryBuilder('instance'); switch (ps.sort) { diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 66502748b3..b799efcd4a 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -5,32 +5,10 @@ import { InstanceEntityService } from '@/core/entities/InstanceEntityService.js' import { UtilityService } from '@/core/UtilityService.js'; import { DI } from '@/di-symbols.js'; -export const meta = { - tags: ['federation'], - - requireCredential: false, - - res: { - oneOf: [{ - type: 'object', - ref: 'FederationInstance', - }, { - type: 'null', - }], - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - host: { type: 'string' }, - }, - required: ['host'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'federation/show-instance'> { + name = 'federation/show-instance' as const; constructor( @Inject(DI.instancesRepository) private instancesRepository: InstancesRepository, @@ -38,7 +16,7 @@ export default class extends Endpoint { private utilityService: UtilityService, private instanceEntityService: InstanceEntityService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const instance = await this.instancesRepository .findOneBy({ host: this.utilityService.toPuny(ps.host) }); diff --git a/packages/backend/src/server/api/endpoints/federation/stats.ts b/packages/backend/src/server/api/endpoints/federation/stats.ts index 19418e698c..11dc7ad325 100644 --- a/packages/backend/src/server/api/endpoints/federation/stats.ts +++ b/packages/backend/src/server/api/endpoints/federation/stats.ts @@ -25,7 +25,8 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'federation/stats'> { + name = 'federation/stats' as const; constructor( @Inject(DI.instancesRepository) private instancesRepository: InstancesRepository, @@ -35,7 +36,7 @@ export default class extends Endpoint { private instanceEntityService: InstanceEntityService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const [topSubInstances, topPubInstances, allSubCount, allPubCount] = await Promise.all([ this.instancesRepository.find({ where: { diff --git a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts index 4596e0c0b5..858a893db0 100644 --- a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts +++ b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts @@ -3,28 +3,15 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { GetterService } from '@/server/api/GetterService.js'; -export const meta = { - tags: ['federation'], - - requireCredential: true, -} as const; - -export const paramDef = { - type: 'object', - properties: { - userId: { type: 'string', format: 'misskey:id' }, - }, - required: ['userId'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'federation/update-remote-user'> { + name = 'federation/update-remote-user' as const; constructor( private getterService: GetterService, private apPersonService: ApPersonService, ) { - super(meta, paramDef, async (ps) => { + super(async (ps) => { const user = await this.getterService.getRemoteUser(ps.userId); await this.apPersonService.updatePerson(user.uri!); }); diff --git a/packages/backend/src/server/api/endpoints/federation/users.ts b/packages/backend/src/server/api/endpoints/federation/users.ts index a028930f21..708ef9b598 100644 --- a/packages/backend/src/server/api/endpoints/federation/users.ts +++ b/packages/backend/src/server/api/endpoints/federation/users.ts @@ -5,36 +5,10 @@ import { QueryService } from '@/core/QueryService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DI } from '@/di-symbols.js'; -export const meta = { - tags: ['federation'], - - requireCredential: false, - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - ref: 'UserDetailedNotMe', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - host: { type: 'string' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - }, - required: ['host'], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'federation/users'> { + name = 'federation/users' as const; constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -42,7 +16,7 @@ export default class extends Endpoint { private userEntityService: UserEntityService, private queryService: QueryService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const query = this.queryService.makePaginationQuery(this.usersRepository.createQueryBuilder('user'), ps.sinceId, ps.untilId) .andWhere('user.host = :host', { host: ps.host }); diff --git a/packages/misskey-js/src/endpoints.ts b/packages/misskey-js/src/endpoints.ts index 236ff8bb09..8c750ff928 100644 --- a/packages/misskey-js/src/endpoints.ts +++ b/packages/misskey-js/src/endpoints.ts @@ -4104,9 +4104,21 @@ export const endpoints = { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, - type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) }, - sort: { type: 'string', nullable: true, enum: ['+createdAt', '-createdAt', '+name', '-name', '+size', '-size'] }, + folderId: { + oneOf: [ + { type: 'string', format: 'misskey:id' }, + { type: 'null' }, + ], + default: null, + }, + type: { + oneOf: [ + { type: 'string', pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) }, + { type: 'null' }, + ], + default: null, + }, + sort: { enum: [null, '+createdAt', '-createdAt', '+name', '-name', '+size', '-size'] }, }, required: [], }, @@ -4132,7 +4144,13 @@ export const endpoints = { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, - folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + folderId: { + oneOf: [ + { type: 'string', format: 'misskey:id' }, + { type: 'null' }, + ], + default: null, + }, }, required: [], }, @@ -4174,9 +4192,9 @@ export const endpoints = { 'email-address/available': { tags: ['users'], - + requireCredential: false, - + defines: [{ req: { type: 'object', @@ -4190,10 +4208,7 @@ export const endpoints = { properties: { available: { type: 'boolean' }, reason: { - oneOf: [ - { type: 'string', enum: ['used', 'format', 'disposable', 'mx', 'smtp'] }, - { type: 'null' }, - ], + enum: [null, 'used', 'format', 'disposable', 'mx', 'smtp'] }, }, required: [ @@ -4203,6 +4218,198 @@ export const endpoints = { }, }], }, + + //#region federation + 'federation/followers': { + tags: ['federation'], + + requireCredential: false, + + defines: [{ + req: { + type: 'object', + properties: { + host: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['host'], + }, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/Following', + }, + } + }] + }, + 'federation/followings': { + tags: ['federation'], + + requireCredential: false, + + defines: [{ + req: { + type: 'object', + properties: { + host: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['host'], + }, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/Following', + }, + } + }] + }, + 'federation/instances': { + tags: ['federation'], + + requireCredential: false, + allowGet: true, + cacheSec: 3600, + + defines: [{ + req: { + type: 'object', + properties: { + host: { type: ['string', 'null'], description: 'Omit or use `null` to not filter by host.' }, + blocked: { type: ['boolean', 'null'] }, + notResponding: { type: ['boolean', 'null'] }, + suspended: { type: ['boolean', 'null'] }, + federating: { type: ['boolean', 'null'] }, + subscribing: { type: ['boolean', 'null'] }, + publishing: { type: ['boolean', 'null'] }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, + offset: { type: 'integer', default: 0 }, + sort: { type: 'string' }, + }, + required: [], + }, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/FederationInstance', + }, + }, + }], + }, + 'federation/show-instance': { + tags: ['federation'], + + requireCredential: false, + + defines: [{ + req: { + type: 'object', + properties: { + host: { type: 'string' }, + }, + required: ['host'], + }, + res: { + oneOf: [{ + $ref: 'https://misskey-hub.net/api/schemas/FederationInstance', + }, { + type: 'null', + }], + } + }] + }, + 'federation/stats': { + tags: ['federation'], + + requireCredential: false, + + allowGet: true, + cacheSec: 60 * 60, + + defines: [{ + req: { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: [], + }, + res: { + type: 'object', + properties: { + topSubInstances: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/FederationInstance', + }, + }, + otherFollowersCount: { + type: 'number', + }, + topPubInstances: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/FederationInstance', + }, + }, + otherFollowingCount: { + type: 'number', + }, + }, + required: [ + 'topSubInstances', + 'otherFollowersCount', + 'topPubInstances', + 'otherFollowingCount', + ], + }, + }], + }, + 'federation/update-remote-user': { + tags: ['federation'], + + requireCredential: true, + + defines: [{ + req: { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], + }, + res: undefined, + }], + }, + 'federation/users': { + tags: ['federation'], + + requireCredential: false, + + defines: [{ + req: { + type: 'object', + properties: { + host: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['host'], + }, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/UserDetailedNotMe', + }, + }, + }], + }, + //#endregion } as const satisfies { [x: string]: IEndpointMeta; }; /**