From 16ffd88ecc16c394fd8bc532c61e6be45b053ca5 Mon Sep 17 00:00:00 2001 From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 31 Dec 2025 22:33:26 +0900 Subject: enhance: 誕生日のユーザーウィジェットで、今日だけに限らず、直近の誕生日ユーザーを表示できるように (#13637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): 「今日誕生日のフォロー中ユーザー」ウィジェットをリファクタリング (cherry picked from commit 24652b9364fd7d898ac176e0da3bb6e957f72328) * fix(backend): 年越しの時期で誕生日検索クエリーが誤動作する問題を修正 (MisskeyIO#577) (cherry picked from commit 38581006be35b4725b235be9f178d2c0c9c5af33) * fix * spdx * delete birthday param on users/following api * 名称を一本化 * Update Changelog * Update Changelog * fix(frontend/WidgetBirthdayFollowings): ユーザーの名前が長いと投稿ボタンがはみ出てしまう問題を修正 (MisskeyIO#582) (cherry picked from commit fa47a545b1b770e5f3e52bb2798d1104da5dd244) * use module css * default 3day * Revert "delete birthday param on users/following api" This reverts commit a47456c1c43410409ed3607ae1d6ebb69a82324b. * Update Changelog * 日付が1ヶ月ズレている問題を修正? * fix: 日付関連のバグを修正 Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com> * build misskey-js types * add comment * Update CHANGELOG.md * migrate * change migration * UPdate Changelog * fix: revert unnecessary changes * :art: * i18n * fix * update changelog * :art: * fix lint * refactor: remove unnecessary classes * fix * fix --------- Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com> Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com> --- CHANGELOG.md | 7 +- locales/ja-JP.yml | 4 +- .../migration/1767169026317-birthday-index.js | 20 ++ .../backend/src/core/entities/UserEntityService.ts | 2 +- packages/backend/src/server/api/endpoint-list.ts | 1 + .../src/server/api/endpoints/users/following.ts | 15 +- .../users/get-following-birthday-users.ts | 167 +++++++++++++++++ .../frontend/src/components/MkUserCardMini.vue | 2 +- .../src/widgets/WidgetBirthdayFollowings.user.vue | 86 +++++++++ .../src/widgets/WidgetBirthdayFollowings.vue | 206 +++++++++++++-------- packages/i18n/src/autogen/locale.ts | 8 +- packages/misskey-js/etc/misskey-js.api.md | 8 + packages/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 | 96 ++++++++++ 16 files changed, 550 insertions(+), 88 deletions(-) create mode 100644 packages/backend/migration/1767169026317-birthday-index.js create mode 100644 packages/backend/src/server/api/endpoints/users/get-following-birthday-users.ts create mode 100644 packages/frontend/src/widgets/WidgetBirthdayFollowings.user.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index db60e06b99..520cb109b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ ## Unreleased +### Note +- `users/following` の `birthday` プロパティは非推奨になりました。代わりに `users/get-following-birthday-users` をご利用ください。 + ### General -- +- Enhance: 「もうすぐ誕生日のユーザー」ウィジェットで、誕生日が至近のユーザーも表示できるように + (Cherry-picked from https://github.com/MisskeyIO/misskey) + - 「今日誕生日のユーザー」は「もうすぐ誕生日のユーザー」に名称変更されました ### Client - Enhance: ドライブのファイル一覧で自動でもっと見るを利用可能に diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index a6edca0b98..e1464151e7 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2600,7 +2600,7 @@ _widgets: _userList: chooseList: "リストを選択" clicker: "クリッカー" - birthdayFollowings: "今日誕生日のユーザー" + birthdayFollowings: "もうすぐ誕生日のユーザー" chat: "ダイレクトメッセージ" _widgetOptions: @@ -2639,6 +2639,8 @@ _widgetOptions: shuffle: "表示順をシャッフル" duration: "ティッカーのスクロール速度(秒)" reverse: "逆方向にスクロール" + _birthdayFollowings: + period: "期間" _cw: hide: "隠す" diff --git a/packages/backend/migration/1767169026317-birthday-index.js b/packages/backend/migration/1767169026317-birthday-index.js new file mode 100644 index 0000000000..972fc08c9b --- /dev/null +++ b/packages/backend/migration/1767169026317-birthday-index.js @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class BirthdayIndex1767169026317 { + name = 'BirthdayIndex1767169026317' + + 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 ac5b855096..0f4051e7b8 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -720,7 +720,7 @@ export class UserEntityService implements OnModuleInit { me, { ...options, - userProfile: profilesMap.get(u.id), + userProfile: profilesMap?.get(u.id), userRelations: userRelations, userMemos: userMemos, pinNotes: pinNotes, diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index 9aecc0f0fd..9311c80eaa 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -391,6 +391,7 @@ export * as 'users/featured-notes' from './endpoints/users/featured-notes.js'; export * as 'users/flashs' from './endpoints/users/flashs.js'; export * as 'users/followers' from './endpoints/users/followers.js'; export * as 'users/following' from './endpoints/users/following.js'; +export * as 'users/get-following-birthday-users' from './endpoints/users/get-following-birthday-users.js'; export * as 'users/gallery/posts' from './endpoints/users/gallery/posts.js'; export * as 'users/get-frequently-replied-users' from './endpoints/users/get-frequently-replied-users.js'; export * as 'users/lists/create' from './endpoints/users/lists/create.js'; diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 047f9a053b..326e56bc85 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -86,7 +86,7 @@ export const paramDef = { sinceDate: { type: 'integer' }, untilDate: { type: 'integer' }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - birthday: { ...birthdaySchema, nullable: true }, + birthday: { ...birthdaySchema, nullable: true, description: '@deprecated use get-following-birthday-users instead.' }, }, }, ], @@ -146,14 +146,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 0000000000..124114244e --- /dev/null +++ b/packages/backend/src/server/api/endpoints/users/get-following-birthday-users.ts @@ -0,0 +1,167 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Brackets } from 'typeorm'; +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: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'misskey:id', + }, + birthday: { + type: 'string', + 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: { + oneOf: [{ + type: 'object', + properties: { + month: { type: 'integer', minimum: 1, maximum: 12 }, + day: { type: 'integer', minimum: 1, maximum: 31 }, + }, + required: ['month', 'day'], + }, { + type: 'object', + properties: { + 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'], + }, + }, + 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 range = ps.birthday as { begin: { month: number; day: number }; end: { month: number; day: number }; }; + + // 誕生日は mmdd の形式の最大4桁の数字(例: 8月30日 → 830)でインデックスが効くようになっているので、その形式に変換 + const begin = range.begin.month * 100 + range.begin.day; + const end = range.end.month * 100 + range.end.day; + + if (begin <= end) { + query.andWhere('get_birthday_date(followeeProfile.birthday) BETWEEN :begin AND :end', { begin, end }); + } else { + // 12/31 から 1/1 の範囲を取得するために OR で対応 + query.andWhere(new Brackets(qb => { + qb.where('get_birthday_date(followeeProfile.birthday) BETWEEN :begin AND 1231', { begin }); + qb.orWhere('get_birthday_date(followeeProfile.birthday) BETWEEN 101 AND :end', { end }); + })); + } + } 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.setHours(0, 0, 0, 0); + // item.birthday_date は mmdd の形式の最大4桁の数字(例: 8月30日 → 830)で出力されるので、日付に戻してDateオブジェクトに設定 + birthday.setMonth(Math.floor(item.birthday_date / 100) - 1, item.birthday_date % 100); + + if (birthday.getTime() < new Date().setHours(0, 0, 0, 0)) { + birthday.setFullYear(new Date().getFullYear() + 1); + } + + const birthdayStr = `${birthday.getFullYear()}-${(birthday.getMonth() + 1).toString().padStart(2, '0')}-${(birthday.getDate()).toString().padStart(2, '0')}`; + return { + id: item.user_id, + birthday: birthdayStr, + user: users.get(item.user_id), + }; + }) + .filter(item => item.user != null) + .map(item => item as { id: string; birthday: string; user: Packed<'UserLite'> }); + }); + } +} diff --git a/packages/frontend/src/components/MkUserCardMini.vue b/packages/frontend/src/components/MkUserCardMini.vue index dde2efd8ee..1fd43bd6e4 100644 --- a/packages/frontend/src/components/MkUserCardMini.vue +++ b/packages/frontend/src/components/MkUserCardMini.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- @{{ acct(user) }} + @{{ acct(user) }}
diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.user.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.user.vue new file mode 100644 index 0000000000..dc8ffcc818 --- /dev/null +++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.user.vue @@ -0,0 +1,86 @@ + + + + + + + diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue index d270f12eaf..ea577f3219 100644 --- a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue +++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue @@ -4,34 +4,43 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/i18n/src/autogen/locale.ts b/packages/i18n/src/autogen/locale.ts index 5a7c0c541f..ca253a5c97 100644 --- a/packages/i18n/src/autogen/locale.ts +++ b/packages/i18n/src/autogen/locale.ts @@ -9885,7 +9885,7 @@ export interface Locale extends ILocale { */ "clicker": string; /** - * 今日誕生日のユーザー + * もうすぐ誕生日のユーザー */ "birthdayFollowings": string; /** @@ -10024,6 +10024,12 @@ export interface Locale extends ILocale { */ "reverse": string; }; + "_birthdayFollowings": { + /** + * 期間 + */ + "period": string; + }; }; "_cw": { /** diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index fe19c00a80..6403fb2748 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2121,6 +2121,8 @@ declare namespace entities { UsersFollowingResponse, UsersGalleryPostsRequest, UsersGalleryPostsResponse, + UsersGetFollowingBirthdayUsersRequest, + UsersGetFollowingBirthdayUsersResponse, UsersGetFrequentlyRepliedUsersRequest, UsersGetFrequentlyRepliedUsersResponse, UsersListsCreateRequest, @@ -3727,6 +3729,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 af3a09a16e..91f7bb5b07 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -4532,6 +4532,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 c3ef3de4e6..8dc3b26bd7 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -616,6 +616,8 @@ import type { UsersFollowingResponse, UsersGalleryPostsRequest, UsersGalleryPostsResponse, + UsersGetFollowingBirthdayUsersRequest, + UsersGetFollowingBirthdayUsersResponse, UsersGetFrequentlyRepliedUsersRequest, UsersGetFrequentlyRepliedUsersResponse, UsersListsCreateRequest, @@ -1067,6 +1069,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/lists/create': { req: UsersListsCreateRequest; res: UsersListsCreateResponse }; 'users/lists/create-from-public': { req: UsersListsCreateFromPublicRequest; res: UsersListsCreateFromPublicResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index 0d57b065dc..e9bb080636 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -619,6 +619,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 UsersListsCreateRequest = operations['users___lists___create']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 2650869590..f3648e5112 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -3717,6 +3717,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 @@ -34847,6 +34856,7 @@ export interface operations { untilDate?: number; /** @default 10 */ limit?: number; + /** @description @deprecated use get-following-birthday-users instead. */ birthday?: string | null; }; }; @@ -34982,6 +34992,92 @@ export interface operations { }; }; }; + '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: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + birthday: string; + user: components['schemas']['UserLite']; + }[]; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; 'users___get-frequently-replied-users': { requestBody: { content: { -- cgit v1.2.3-freya