From 24652b9364fd7d898ac176e0da3bb6e957f72328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=BE=E3=81=A3=E3=81=A1=E3=82=83=E3=81=A8=E3=83=BC?= =?UTF-8?q?=E3=81=AB=E3=82=85?= <17376330+u1-liquid@users.noreply.github.com> Date: Fri, 29 Mar 2024 02:28:22 +0900 Subject: [PATCH] =?UTF-8?q?enhance(frontend):=20=E3=80=8C=E4=BB=8A?= =?UTF-8?q?=E6=97=A5=E8=AA=95=E7=94=9F=E6=97=A5=E3=81=AE=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E4=B8=AD=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E3=80=8D=E3=82=A6=E3=82=A3=E3=82=B8=E3=82=A7=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=82=92=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF=E3=83=AA?= =?UTF-8?q?=E3=83=B3=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/en-US.yml | 1 + locales/index.d.ts | 4 + locales/ja-JP.yml | 1 + locales/ko-KR.yml | 1 + .../migration/1711478468155-birthday-index.js | 15 ++ .../src/core/entities/UserEntityService.ts | 6 +- .../backend/src/server/api/EndpointsModule.ts | 4 + packages/backend/src/server/api/endpoints.ts | 2 + .../server/api/endpoints/users/following.ts | 18 +- .../users/get-following-birthday-users.ts | 130 +++++++++++ .../src/server/api/endpoints/users/show.ts | 16 +- .../frontend/src/components/MkAvatars.vue | 1 + .../src/widgets/WidgetBirthdayFollowings.vue | 219 +++++++++++------- packages/misskey-js/etc/misskey-js.api.md | 8 + .../misskey-js/src/autogen/apiClientJSDoc.ts | 11 + packages/misskey-js/src/autogen/endpoint.ts | 3 + packages/misskey-js/src/autogen/entities.ts | 2 + packages/misskey-js/src/autogen/types.ts | 86 ++++++- 18 files changed, 434 insertions(+), 94 deletions(-) create mode 100644 packages/backend/migration/1711478468155-birthday-index.js create mode 100644 packages/backend/src/server/api/endpoints/users/get-following-birthday-users.ts diff --git a/locales/en-US.yml b/locales/en-US.yml index f90dcc0e2..a44447a25 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -2153,6 +2153,7 @@ _widgets: chooseList: "Select a list" clicker: "Clicker" birthdayFollowings: "Users who celebrate their birthday today" + birthdaySoon: "Users who will celebrate their birthday soon" _cw: hide: "Hide" show: "Show content" diff --git a/locales/index.d.ts b/locales/index.d.ts index e523dbcee..70beffa0c 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -8396,6 +8396,10 @@ export interface Locale extends ILocale { * 今日誕生日のユーザー */ "birthdayFollowings": string; + /** + * もうすぐ誕生日のユーザー + */ + "birthdaySoon": string; }; "_cw": { /** diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 34b11a8b0..ec4f688eb 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2207,6 +2207,7 @@ _widgets: chooseList: "リストを選択" clicker: "クリッカー" birthdayFollowings: "今日誕生日のユーザー" + birthdaySoon: "もうすぐ誕生日のユーザー" _cw: hide: "隠す" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 09bb3e32b..a736dcc23 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -2131,6 +2131,7 @@ _widgets: chooseList: "리스트 선택" clicker: "클리커" birthdayFollowings: "오늘이 생일인 사용자" + birthdaySoon: "곧 생일인 사용자" _cw: hide: "숨기기" show: "더 보기" diff --git a/packages/backend/migration/1711478468155-birthday-index.js b/packages/backend/migration/1711478468155-birthday-index.js new file mode 100644 index 000000000..7954e3cd2 --- /dev/null +++ b/packages/backend/migration/1711478468155-birthday-index.js @@ -0,0 +1,15 @@ +export class BirthdayIndex1711478468155 { + name = 'BirthdayIndex1711478468155' + + async up(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_de22cd2b445eee31ae51cdbe99"`); + await queryRunner.query(`CREATE OR REPLACE FUNCTION get_birthday_date(birthday TEXT) RETURNS SMALLINT AS $$ BEGIN RETURN CAST((SUBSTR(birthday, 6, 2) || SUBSTR(birthday, 9, 2)) AS SMALLINT); END; $$ LANGUAGE plpgsql IMMUTABLE;`); + await queryRunner.query(`CREATE INDEX "IDX_USERPROFILE_BIRTHDAY_DATE" ON "user_profile" (get_birthday_date("birthday"))`); + } + + async down(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_de22cd2b445eee31ae51cdbe99" ON "user_profile" (substr("birthday", 6, 5))`); + await queryRunner.query(`DROP INDEX "public"."IDX_USERPROFILE_BIRTHDAY_DATE"`); + await queryRunner.query(`DROP FUNCTION IF EXISTS get_birthday_date(birthday TEXT)`); + } +} diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 225824f93..892529f7c 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -642,8 +642,8 @@ export class UserEntityService implements OnModuleInit { // -- 特に前提条件のない値群を取得 - const profilesMap = await this.userProfilesRepository.findBy({ userId: In(_userIds) }) - .then(profiles => new Map(profiles.map(p => [p.userId, p]))); + const profilesMap = (options?.schema !== 'UserLite') ? await this.userProfilesRepository.findBy({ userId: In(_userIds) }) + .then(profiles => new Map(profiles.map(p => [p.userId, p]))) : undefined; // -- 実行者の有無や指定スキーマの種別によって要否が異なる値群を取得 @@ -680,7 +680,7 @@ export class UserEntityService implements OnModuleInit { } } - return (await Promise.allSettled(_users.map(u => this.pack(u, me, { ...options, userProfile: profilesMap.get(u.id), userRelations: userRelations, userMemos: userMemos, pinNotes: pinNotes })))) + return (await Promise.allSettled(_users.map(u => this.pack(u, me, { ...options, userProfile: profilesMap?.get(u.id), userRelations: userRelations, userMemos: userMemos, pinNotes: pinNotes })))) .filter(result => result.status === 'fulfilled') .map(result => (result as PromiseFulfilledResult>).value); } diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 313d2cd04..7842f0e28 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -348,6 +348,7 @@ import * as ep___users_clips from './endpoints/users/clips.js'; import * as ep___users_followers from './endpoints/users/followers.js'; import * as ep___users_following from './endpoints/users/following.js'; import * as ep___users_gallery_posts from './endpoints/users/gallery/posts.js'; +import * as ep___users_getFollowingBirthdayUsers from './endpoints/users/get-following-birthday-users.js'; import * as ep___users_getFrequentlyRepliedUsers from './endpoints/users/get-frequently-replied-users.js'; import * as ep___users_featuredNotes from './endpoints/users/featured-notes.js'; import * as ep___users_lists_create from './endpoints/users/lists/create.js'; @@ -733,6 +734,7 @@ const $users_clips: Provider = { provide: 'ep:users/clips', useClass: ep___users const $users_followers: Provider = { provide: 'ep:users/followers', useClass: ep___users_followers.default }; const $users_following: Provider = { provide: 'ep:users/following', useClass: ep___users_following.default }; const $users_gallery_posts: Provider = { provide: 'ep:users/gallery/posts', useClass: ep___users_gallery_posts.default }; +const $users_getFollowingBirthdayUsers: Provider = { provide: 'ep:users/get-following-birthday-users', useClass: ep___users_getFollowingBirthdayUsers.default }; const $users_getFrequentlyRepliedUsers: Provider = { provide: 'ep:users/get-frequently-replied-users', useClass: ep___users_getFrequentlyRepliedUsers.default }; const $users_featuredNotes: Provider = { provide: 'ep:users/featured-notes', useClass: ep___users_featuredNotes.default }; const $users_lists_create: Provider = { provide: 'ep:users/lists/create', useClass: ep___users_lists_create.default }; @@ -1122,6 +1124,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $users_followers, $users_following, $users_gallery_posts, + $users_getFollowingBirthdayUsers, $users_getFrequentlyRepliedUsers, $users_featuredNotes, $users_lists_create, @@ -1503,6 +1506,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $users_followers, $users_following, $users_gallery_posts, + $users_getFollowingBirthdayUsers, $users_getFrequentlyRepliedUsers, $users_featuredNotes, $users_lists_create, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 4160490e6..be8c4f080 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -348,6 +348,7 @@ import * as ep___users_clips from './endpoints/users/clips.js'; import * as ep___users_followers from './endpoints/users/followers.js'; import * as ep___users_following from './endpoints/users/following.js'; import * as ep___users_gallery_posts from './endpoints/users/gallery/posts.js'; +import * as ep___users_getFollowingBirthdayUsers from './endpoints/users/get-following-birthday-users.js'; import * as ep___users_getFrequentlyRepliedUsers from './endpoints/users/get-frequently-replied-users.js'; import * as ep___users_featuredNotes from './endpoints/users/featured-notes.js'; import * as ep___users_lists_create from './endpoints/users/lists/create.js'; @@ -731,6 +732,7 @@ const eps = [ ['users/followers', ep___users_followers], ['users/following', ep___users_following], ['users/gallery/posts', ep___users_gallery_posts], + ['users/get-following-birthday-users', ep___users_getFollowingBirthdayUsers], ['users/get-frequently-replied-users', ep___users_getFrequentlyRepliedUsers], ['users/featured-notes', ep___users_featuredNotes], ['users/lists/create', ep___users_lists_create], diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 6b3389f0b..084d27809 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -67,7 +67,10 @@ export const paramDef = { description: 'The local host is represented with `null`.', }, - birthday: { ...birthdaySchema, nullable: true }, + birthday: { + ...birthdaySchema, nullable: true, + description: '@deprecated use get-following-birthday-users instead.', + }, }, anyOf: [ { required: ['userId'] }, @@ -126,14 +129,15 @@ export default class extends Endpoint { // eslint- .andWhere('following.followerId = :userId', { userId: user.id }) .innerJoinAndSelect('following.followee', 'followee'); + // @deprecated use get-following-birthday-users instead. if (ps.birthday) { - try { - const birthday = ps.birthday.substring(5, 10); - const birthdayUserQuery = this.userProfilesRepository.createQueryBuilder('user_profile'); - birthdayUserQuery.select('user_profile.userId') - .where(`SUBSTR(user_profile.birthday, 6, 5) = '${birthday}'`); + query.innerJoin(this.userProfilesRepository.metadata.targetName, 'followeeProfile', 'followeeProfile.userId = following.followeeId'); - query.andWhere(`following.followeeId IN (${ birthdayUserQuery.getQuery() })`); + try { + const birthday = ps.birthday.split('-'); + birthday.shift(); // 年の部分を削除 + // なぜか get_birthday_date() = :birthday だとインデックスが効かないので、BETWEEN で対応 + query.andWhere('get_birthday_date(followeeProfile.birthday) BETWEEN :birthday AND :birthday', { birthday: parseInt(birthday.join('')) }); } catch (err) { throw new ApiError(meta.errors.birthdayInvalid); } diff --git a/packages/backend/src/server/api/endpoints/users/get-following-birthday-users.ts b/packages/backend/src/server/api/endpoints/users/get-following-birthday-users.ts new file mode 100644 index 000000000..84357bca3 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/users/get-following-birthday-users.ts @@ -0,0 +1,130 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { DI } from '@/di-symbols.js'; +import type { + FollowingsRepository, + UserProfilesRepository, +} from '@/models/_.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import type { Packed } from '@/misc/json-schema.js'; + +export const meta = { + tags: ['users'], + + requireCredential: true, + kind: 'read:account', + + description: 'Find users who have a birthday on the specified range.', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + properties: { + birthday: { + type: 'string', format: 'date-time', + optional: false, nullable: false, + }, + user: { + type: 'object', + optional: false, nullable: false, + ref: 'UserLite', + }, + }, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + birthday: { + type: 'object', + properties: { + month: { type: 'integer', minimum: 1, maximum: 12 }, + day: { type: 'integer', minimum: 1, maximum: 31 }, + begin: { + type: 'object', + properties: { + month: { type: 'integer', minimum: 1, maximum: 12 }, + day: { type: 'integer', minimum: 1, maximum: 31 }, + }, + required: ['month', 'day'], + }, + end: { + type: 'object', + properties: { + month: { type: 'integer', minimum: 1, maximum: 12 }, + day: { type: 'integer', minimum: 1, maximum: 31 }, + }, + required: ['month', 'day'], + }, + }, + anyOf: [ + { required: ['month', 'day'] }, + { required: ['begin', 'end'] }, + ], + }, + }, + required: ['birthday'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + @Inject(DI.followingsRepository) + private followingsRepository: FollowingsRepository, + + private userEntityService: UserEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.followingsRepository + .createQueryBuilder('following') + .andWhere('following.followerId = :userId', { userId: me.id }) + .innerJoin(this.userProfilesRepository.metadata.targetName, 'followeeProfile', 'followeeProfile.userId = following.followeeId'); + + if (Object.hasOwn(ps.birthday, 'begin') && Object.hasOwn(ps.birthday, 'end')) { + const { begin, end } = ps.birthday as { begin: { month: number; day: number }; end: { month: number; day: number }; }; + query.andWhere('get_birthday_date(followeeProfile.birthday) BETWEEN :begin AND :end', { begin: begin.month * 100 + begin.day, end: end.month * 100 + end.day }); + } else { + const { month, day } = ps.birthday as { month: number; day: number }; + // なぜか get_birthday_date() = :birthday だとインデックスが効かないので、BETWEEN で対応 + query.andWhere('get_birthday_date(followeeProfile.birthday) BETWEEN :birthday AND :birthday', { birthday: month * 100 + day }); + } + + query.select('following.followeeId', 'user_id'); + query.addSelect('get_birthday_date(followeeProfile.birthday)', 'birthday_date'); + query.orderBy('birthday_date', 'ASC'); + + const birthdayUsers = await query + .offset(ps.offset).limit(ps.limit) + .getRawMany<{ birthday_date: number; user_id: string }>(); + + const users = new Map>(( + await this.userEntityService.packMany( + birthdayUsers.map(u => u.user_id), + me, + { schema: 'UserLite' }, + ) + ).map(u => [u.id, u])); + + return birthdayUsers + .map(item => { + const birthday = new Date(); + birthday.setMonth(Math.floor(item.birthday_date / 100) - 1); + birthday.setDate(item.birthday_date % 100); + birthday.setHours(0, 0, 0, 0); + if (birthday.getTime() < Date.now()) birthday.setFullYear(new Date().getFullYear() + 1); + return { birthday: birthday.toISOString(), user: users.get(item.user_id) }; + }) + .filter(item => item.user !== undefined) + .map(item => item as { birthday: string; user: Packed<'UserLite'> }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 53e2e4b22..ff18c9187 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -27,10 +27,21 @@ export const meta = { res: { optional: false, nullable: false, oneOf: [ + { + type: 'object', + ref: 'UserLite', + }, { type: 'object', ref: 'UserDetailed', }, + { + type: 'array', + items: { + type: 'object', + ref: 'UserLite', + }, + }, { type: 'array', items: { @@ -71,6 +82,7 @@ export const paramDef = { nullable: true, description: 'The local host is represented with `null`.', }, + detailed: { type: 'boolean', default: true }, }, anyOf: [ { required: ['userId'] }, @@ -117,7 +129,7 @@ export default class extends Endpoint { // eslint- } return await this.userEntityService.packMany(_users, me, { - schema: 'UserDetailed', + schema: ps.detailed ? 'UserDetailed' : 'UserLite', }); } else { // Lookup user @@ -147,7 +159,7 @@ export default class extends Endpoint { // eslint- } return await this.userEntityService.pack(user, me, { - schema: 'UserDetailed', + schema: ps.detailed ? 'UserDetailed' : 'UserLite', }); } }); diff --git a/packages/frontend/src/components/MkAvatars.vue b/packages/frontend/src/components/MkAvatars.vue index 8236d0ddb..fe1545313 100644 --- a/packages/frontend/src/components/MkAvatars.vue +++ b/packages/frontend/src/components/MkAvatars.vue @@ -29,6 +29,7 @@ const users = ref([]); onMounted(async () => { users.value = await misskeyApi('users/show', { userIds: props.userIds, + detailed: false, }) as unknown as Misskey.entities.UserLite[]; }); diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue index 49fd103d3..1247a02af 100644 --- a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue +++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue @@ -4,43 +4,76 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 1a3ad3bdf..3289b4f7c 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1686,6 +1686,8 @@ declare namespace entities { UsersFollowingResponse, UsersGalleryPostsRequest, UsersGalleryPostsResponse, + UsersGetFollowingBirthdayUsersRequest, + UsersGetFollowingBirthdayUsersResponse, UsersGetFrequentlyRepliedUsersRequest, UsersGetFrequentlyRepliedUsersResponse, UsersFeaturedNotesRequest, @@ -3091,6 +3093,12 @@ type UsersGalleryPostsRequest = operations['users___gallery___posts']['requestBo // @public (undocumented) type UsersGalleryPostsResponse = operations['users___gallery___posts']['responses']['200']['content']['application/json']; +// @public (undocumented) +type UsersGetFollowingBirthdayUsersRequest = operations['users___get-following-birthday-users']['requestBody']['content']['application/json']; + +// @public (undocumented) +type UsersGetFollowingBirthdayUsersResponse = operations['users___get-following-birthday-users']['responses']['200']['content']['application/json']; + // @public (undocumented) type UsersGetFrequentlyRepliedUsersRequest = operations['users___get-frequently-replied-users']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index 053474b00..35d746190 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -3804,6 +3804,17 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * Find users who have a birthday on the specified range. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * Get a list of other users that the specified user frequently replies to. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 9d9a99083..2dd65df9a 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -506,6 +506,8 @@ import type { UsersFollowingResponse, UsersGalleryPostsRequest, UsersGalleryPostsResponse, + UsersGetFollowingBirthdayUsersRequest, + UsersGetFollowingBirthdayUsersResponse, UsersGetFrequentlyRepliedUsersRequest, UsersGetFrequentlyRepliedUsersResponse, UsersFeaturedNotesRequest, @@ -916,6 +918,7 @@ export type Endpoints = { 'users/followers': { req: UsersFollowersRequest; res: UsersFollowersResponse }; 'users/following': { req: UsersFollowingRequest; res: UsersFollowingResponse }; 'users/gallery/posts': { req: UsersGalleryPostsRequest; res: UsersGalleryPostsResponse }; + 'users/get-following-birthday-users': { req: UsersGetFollowingBirthdayUsersRequest; res: UsersGetFollowingBirthdayUsersResponse }; 'users/get-frequently-replied-users': { req: UsersGetFrequentlyRepliedUsersRequest; res: UsersGetFrequentlyRepliedUsersResponse }; 'users/featured-notes': { req: UsersFeaturedNotesRequest; res: UsersFeaturedNotesResponse }; 'users/lists/create': { req: UsersListsCreateRequest; res: UsersListsCreateResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index 87c8b8def..2c9afc650 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -509,6 +509,8 @@ export type UsersFollowingRequest = operations['users___following']['requestBody export type UsersFollowingResponse = operations['users___following']['responses']['200']['content']['application/json']; export type UsersGalleryPostsRequest = operations['users___gallery___posts']['requestBody']['content']['application/json']; export type UsersGalleryPostsResponse = operations['users___gallery___posts']['responses']['200']['content']['application/json']; +export type UsersGetFollowingBirthdayUsersRequest = operations['users___get-following-birthday-users']['requestBody']['content']['application/json']; +export type UsersGetFollowingBirthdayUsersResponse = operations['users___get-following-birthday-users']['responses']['200']['content']['application/json']; export type UsersGetFrequentlyRepliedUsersRequest = operations['users___get-frequently-replied-users']['requestBody']['content']['application/json']; export type UsersGetFrequentlyRepliedUsersResponse = operations['users___get-frequently-replied-users']['responses']['200']['content']['application/json']; export type UsersFeaturedNotesRequest = operations['users___featured-notes']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 94f60821e..83250ce4a 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -3276,6 +3276,15 @@ export type paths = { */ post: operations['users___gallery___posts']; }; + '/users/get-following-birthday-users': { + /** + * users/get-following-birthday-users + * @description Find users who have a birthday on the specified range. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + post: operations['users___get-following-birthday-users']; + }; '/users/get-frequently-replied-users': { /** * users/get-frequently-replied-users @@ -25425,6 +25434,7 @@ export type operations = { username?: string; /** @description The local host is represented with `null`. */ host?: string | null; + /** @description @deprecated use get-following-birthday-users instead. */ birthday?: string | null; }; }; @@ -25528,6 +25538,78 @@ export type operations = { }; }; }; + /** + * users/get-following-birthday-users + * @description Find users who have a birthday on the specified range. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + 'users___get-following-birthday-users': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** @default 0 */ + offset?: number; + birthday: { + month?: number; + day?: number; + begin?: { + month: number; + day: number; + }; + end?: { + month: number; + day: number; + }; + }; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: date-time */ + birthday: string; + user: components['schemas']['UserLite']; + }[]; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * users/get-frequently-replied-users * @description Get a list of other users that the specified user frequently replies to. @@ -26896,6 +26978,8 @@ export type operations = { username?: string; /** @description The local host is represented with `null`. */ host?: string | null; + /** @default true */ + detailed?: boolean; }; }; }; @@ -26903,7 +26987,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['UserDetailed'] | components['schemas']['UserDetailed'][]; + 'application/json': components['schemas']['UserLite'] | components['schemas']['UserDetailed'] | components['schemas']['UserLite'][] | components['schemas']['UserDetailed'][]; }; }; /** @description Client error */