mirror of
https://github.com/MisskeyIO/misskey
synced 2024-11-27 14:28:49 +09:00
feat(frontend): Misskey Gamesのリストに鯖缶指定のチャンネルを載せる (MisskeyIO#383)
This commit is contained in:
parent
7884901950
commit
ac79f1fdc1
@ -376,6 +376,8 @@ pinnedPages: "Pinned Pages"
|
||||
pinnedPagesDescription: "Enter the paths of the Pages you want to pin to the top page of this instance, separated by line breaks."
|
||||
pinnedClipId: "ID of the clip to pin"
|
||||
pinnedNotes: "Pinned notes"
|
||||
featuredGameChannels: "Featured Misskey Games Channels"
|
||||
featuredGameChannelsDescription: "Enter the channels you want to pin to Misskey Games, separated by line breaks."
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "Enable hCaptcha"
|
||||
hcaptchaSiteKey: "Site key"
|
||||
|
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
@ -1536,6 +1536,14 @@ export interface Locale extends ILocale {
|
||||
* ピン留めされたノート
|
||||
*/
|
||||
"pinnedNotes": string;
|
||||
/**
|
||||
* Misskey Gamesのピン留めチャンネル
|
||||
*/
|
||||
"featuredGameChannels": string;
|
||||
/**
|
||||
* Misskey Gamesにピン留めしたいチャンネルを改行で区切って記述します。
|
||||
*/
|
||||
"featuredGameChannelsDescription": string;
|
||||
/**
|
||||
* hCaptcha
|
||||
*/
|
||||
|
@ -380,6 +380,8 @@ pinnedPages: "ピン留めページ"
|
||||
pinnedPagesDescription: "サーバーのトップページにピン留めしたいページのパスを改行で区切って記述します。"
|
||||
pinnedClipId: "ピン留めするクリップのID"
|
||||
pinnedNotes: "ピン留めされたノート"
|
||||
featuredGameChannels: "Misskey Gamesのピン留めチャンネル"
|
||||
featuredGameChannelsDescription: "Misskey Gamesにピン留めしたいチャンネルを改行で区切って記述します。"
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "hCaptchaを有効にする"
|
||||
hcaptchaSiteKey: "サイトキー"
|
||||
|
@ -379,6 +379,8 @@ pinnedPages: "고정한 페이지"
|
||||
pinnedPagesDescription: "서버의 대문에 고정하고 싶은 페이지의 경로를 한 줄에 하나씩 적습니다."
|
||||
pinnedClipId: "고정할 클립의 ID"
|
||||
pinnedNotes: "고정된 노트"
|
||||
featuredGameChannels: "Misskey Games에 고정할 채널"
|
||||
featuredGameChannelsDescription: "Misskey Games에 고정할 채널을 한 줄에 하나씩 적습니다."
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "hCaptcha 활성화"
|
||||
hcaptchaSiteKey: "사이트 키"
|
||||
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class FeaturedGamesChannel1706081039979 {
|
||||
name = 'FeaturedGamesChannel1706081039979'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "featuredGameChannels" character varying(1024) array NOT NULL DEFAULT '{}'`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "featuredGameChannels"`);
|
||||
}
|
||||
}
|
@ -97,5 +97,14 @@ export class ChannelEntityService {
|
||||
} : {}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public async packMany(
|
||||
channels: (MiChannel['id'] | MiChannel)[],
|
||||
me: { id: MiUser['id'] } | null | undefined,
|
||||
detailed?: boolean,
|
||||
): Promise<Packed<'Channel'>[]> {
|
||||
return (await Promise.allSettled(channels.map(x => this.pack(x, me, detailed))))
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => (result as PromiseFulfilledResult<Packed<'Channel'>>).value);
|
||||
}
|
||||
}
|
||||
|
@ -591,4 +591,9 @@ export class MiMeta {
|
||||
length: 3072, array: true, default: '{}',
|
||||
})
|
||||
public urlPreviewDenyList: string[];
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024, array: true, default: '{}',
|
||||
})
|
||||
public featuredGameChannels: string[];
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ import * as ep___blocking_delete from './endpoints/blocking/delete.js';
|
||||
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
||||
import * as ep___channels_create from './endpoints/channels/create.js';
|
||||
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
||||
import * as ep___channels_featured_games from './endpoints/channels/featured-games.js';
|
||||
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
||||
import * as ep___channels_followed from './endpoints/channels/followed.js';
|
||||
import * as ep___channels_owned from './endpoints/channels/owned.js';
|
||||
@ -482,6 +483,7 @@ const $blocking_delete: Provider = { provide: 'ep:blocking/delete', useClass: ep
|
||||
const $blocking_list: Provider = { provide: 'ep:blocking/list', useClass: ep___blocking_list.default };
|
||||
const $channels_create: Provider = { provide: 'ep:channels/create', useClass: ep___channels_create.default };
|
||||
const $channels_featured: Provider = { provide: 'ep:channels/featured', useClass: ep___channels_featured.default };
|
||||
const $channels_featured_games: Provider = { provide: 'ep:channels/featured-games', useClass: ep___channels_featured_games.default };
|
||||
const $channels_follow: Provider = { provide: 'ep:channels/follow', useClass: ep___channels_follow.default };
|
||||
const $channels_followed: Provider = { provide: 'ep:channels/followed', useClass: ep___channels_followed.default };
|
||||
const $channels_owned: Provider = { provide: 'ep:channels/owned', useClass: ep___channels_owned.default };
|
||||
@ -862,6 +864,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||
$blocking_list,
|
||||
$channels_create,
|
||||
$channels_featured,
|
||||
$channels_featured_games,
|
||||
$channels_follow,
|
||||
$channels_followed,
|
||||
$channels_owned,
|
||||
@ -1236,6 +1239,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||
$blocking_list,
|
||||
$channels_create,
|
||||
$channels_featured,
|
||||
$channels_featured_games,
|
||||
$channels_follow,
|
||||
$channels_followed,
|
||||
$channels_owned,
|
||||
|
@ -107,6 +107,7 @@ import * as ep___blocking_delete from './endpoints/blocking/delete.js';
|
||||
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
||||
import * as ep___channels_create from './endpoints/channels/create.js';
|
||||
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
||||
import * as ep___channels_featured_games from './endpoints/channels/featured-games.js';
|
||||
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
||||
import * as ep___channels_followed from './endpoints/channels/followed.js';
|
||||
import * as ep___channels_owned from './endpoints/channels/owned.js';
|
||||
@ -481,6 +482,7 @@ const eps = [
|
||||
['blocking/list', ep___blocking_list],
|
||||
['channels/create', ep___channels_create],
|
||||
['channels/featured', ep___channels_featured],
|
||||
['channels/featured-games', ep___channels_featured_games],
|
||||
['channels/follow', ep___channels_follow],
|
||||
['channels/followed', ep___channels_followed],
|
||||
['channels/owned', ep___channels_owned],
|
||||
|
@ -382,6 +382,13 @@ export const meta = {
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
featuredGameChannels: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
backgroundImageUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
@ -589,6 +596,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
|
||||
notesPerOneAd: instance.notesPerOneAd,
|
||||
urlPreviewDenyList: instance.urlPreviewDenyList,
|
||||
featuredGameChannels: instance.featuredGameChannels,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -150,9 +150,16 @@ export const paramDef = {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
urlPreviewDenyList: { type: 'array', nullable: true, items: {
|
||||
urlPreviewDenyList: {
|
||||
type: 'array', nullable: true, items: {
|
||||
type: 'string',
|
||||
} },
|
||||
},
|
||||
},
|
||||
featuredGameChannels: {
|
||||
type: 'array', nullable: true, items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
@ -208,6 +215,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
set.urlPreviewDenyList = ps.urlPreviewDenyList.filter(Boolean);
|
||||
}
|
||||
|
||||
if (Array.isArray(ps.featuredGameChannels)) {
|
||||
set.featuredGameChannels = ps.featuredGameChannels.filter(Boolean);
|
||||
}
|
||||
|
||||
if (ps.themeColor !== undefined) {
|
||||
set.themeColor = ps.themeColor;
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { In } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { ChannelsRepository } from '@/models/_.js';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['channels'],
|
||||
|
||||
requireCredential: false,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'Channel',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
@Inject(DI.channelsRepository)
|
||||
private channelsRepository: ChannelsRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
private channelEntityService: ChannelEntityService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
if (meta.featuredGameChannels.length === 0) return [];
|
||||
|
||||
const channels = await this.channelsRepository.findBy({
|
||||
id: In(meta.featuredGameChannels)
|
||||
});
|
||||
|
||||
return await this.channelEntityService.packMany(channels, me);
|
||||
});
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
|
||||
const channels = await query.limit(10).getMany();
|
||||
|
||||
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
|
||||
return await this.channelEntityService.packMany(channels, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -48,14 +48,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
private queryService: QueryService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const query = this.queryService.makePaginationQuery(this.channelFollowingsRepository.createQueryBuilder(), ps.sinceId, ps.untilId)
|
||||
.andWhere({ followerId: me.id });
|
||||
const query = this.queryService.makePaginationQuery(this.channelFollowingsRepository.createQueryBuilder('followings'), ps.sinceId, ps.untilId)
|
||||
.andWhere('followings.followerId = :meId', { meId: me.id })
|
||||
.innerJoinAndSelect('followings.followee', 'channel');
|
||||
|
||||
const followings = await query
|
||||
.limit(ps.limit)
|
||||
.getMany();
|
||||
|
||||
return await Promise.all(followings.map(x => this.channelEntityService.pack(x.followeeId, me)));
|
||||
return await this.channelEntityService.packMany(followings.map(x => x.followee!), me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -45,12 +45,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const query = this.channelFavoritesRepository.createQueryBuilder('favorite')
|
||||
.andWhere('favorite.userId = :meId', { meId: me.id })
|
||||
.leftJoinAndSelect('favorite.channel', 'channel');
|
||||
.innerJoinAndSelect('favorite.channel', 'channel');
|
||||
|
||||
const favorites = await query
|
||||
.getMany();
|
||||
|
||||
return await Promise.all(favorites.map(x => this.channelEntityService.pack(x.channel!, me)));
|
||||
return await this.channelEntityService.packMany(favorites.map(x => x.channel!), me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
.limit(ps.limit)
|
||||
.getMany();
|
||||
|
||||
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
|
||||
return await this.channelEntityService.packMany(channels, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
.limit(ps.limit)
|
||||
.getMany();
|
||||
|
||||
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
|
||||
return await this.channelEntityService.packMany(channels, me);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
|
||||
</MkTextarea>
|
||||
|
||||
<MkTextarea v-model="featuredGameChannels">
|
||||
<template #label>{{ i18n.ts.featuredGameChannels }}</template>
|
||||
<template #caption>{{ i18n.ts.featuredGameChannelsDescription }}</template>
|
||||
</MkTextarea>
|
||||
|
||||
<FormSection>
|
||||
<template #label>{{ i18n.ts.files }}</template>
|
||||
|
||||
@ -171,6 +176,7 @@ const maintainerName = ref<string | null>(null);
|
||||
const maintainerEmail = ref<string | null>(null);
|
||||
const impressumUrl = ref<string | null>(null);
|
||||
const pinnedUsers = ref<string>('');
|
||||
const featuredGameChannels = ref<string>('');
|
||||
const cacheRemoteFiles = ref<boolean>(false);
|
||||
const cacheRemoteSensitiveFiles = ref<boolean>(false);
|
||||
const enableServiceWorker = ref<boolean>(false);
|
||||
@ -193,6 +199,7 @@ async function init(): Promise<void> {
|
||||
maintainerEmail.value = meta.maintainerEmail;
|
||||
impressumUrl.value = meta.impressumUrl;
|
||||
pinnedUsers.value = meta.pinnedUsers.join('\n');
|
||||
featuredGameChannels.value = meta.featuredGameChannels.join('\n');
|
||||
cacheRemoteFiles.value = meta.cacheRemoteFiles;
|
||||
cacheRemoteSensitiveFiles.value = meta.cacheRemoteSensitiveFiles;
|
||||
enableServiceWorker.value = meta.enableServiceWorker;
|
||||
@ -216,6 +223,7 @@ async function save(): void {
|
||||
maintainerEmail: maintainerEmail.value,
|
||||
impressumUrl: impressumUrl.value,
|
||||
pinnedUsers: pinnedUsers.value.split('\n'),
|
||||
featuredGameChannels: featuredGameChannels.value.split('\n'),
|
||||
cacheRemoteFiles: cacheRemoteFiles.value,
|
||||
cacheRemoteSensitiveFiles: cacheRemoteSensitiveFiles.value,
|
||||
enableServiceWorker: enableServiceWorker.value,
|
||||
|
@ -19,16 +19,25 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkA>
|
||||
</div>
|
||||
</div>
|
||||
<MkPagination v-slot="{items}" :pagination="featuredPagination">
|
||||
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_margin" :channel="channel"/>
|
||||
</MkPagination>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||
|
||||
definePageMetadata({
|
||||
title: 'Misskey Games',
|
||||
icon: 'ti ti-device-gamepad',
|
||||
});
|
||||
|
||||
const featuredPagination = {
|
||||
endpoint: 'channels/featured-games' as const,
|
||||
noPaging: true,
|
||||
};
|
||||
</script>
|
||||
|
@ -722,6 +722,9 @@ type ChannelsCreateResponse = operations['channels/create']['responses']['200'][
|
||||
// @public (undocumented)
|
||||
type ChannelsFavoriteRequest = operations['channels/favorite']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type ChannelsFeaturedGamesResponse = operations['channels/featured-games']['responses']['200']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
|
||||
|
||||
@ -1246,6 +1249,7 @@ declare namespace entities {
|
||||
ChannelsCreateRequest,
|
||||
ChannelsCreateResponse,
|
||||
ChannelsFeaturedResponse,
|
||||
ChannelsFeaturedGamesResponse,
|
||||
ChannelsFollowRequest,
|
||||
ChannelsFollowedRequest,
|
||||
ChannelsFollowedResponse,
|
||||
|
@ -1109,6 +1109,17 @@ declare module '../api.js' {
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
* **Credential required**: *No*
|
||||
*/
|
||||
request<E extends 'channels/featured-games', P extends Endpoints[E]['req']>(
|
||||
endpoint: E,
|
||||
params: P,
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
|
@ -145,6 +145,7 @@ import type {
|
||||
ChannelsCreateRequest,
|
||||
ChannelsCreateResponse,
|
||||
ChannelsFeaturedResponse,
|
||||
ChannelsFeaturedGamesResponse,
|
||||
ChannelsFollowRequest,
|
||||
ChannelsFollowedRequest,
|
||||
ChannelsFollowedResponse,
|
||||
@ -666,6 +667,7 @@ export type Endpoints = {
|
||||
'blocking/list': { req: BlockingListRequest; res: BlockingListResponse };
|
||||
'channels/create': { req: ChannelsCreateRequest; res: ChannelsCreateResponse };
|
||||
'channels/featured': { req: EmptyRequest; res: ChannelsFeaturedResponse };
|
||||
'channels/featured-games': { req: EmptyRequest; res: ChannelsFeaturedGamesResponse };
|
||||
'channels/follow': { req: ChannelsFollowRequest; res: EmptyResponse };
|
||||
'channels/followed': { req: ChannelsFollowedRequest; res: ChannelsFollowedResponse };
|
||||
'channels/owned': { req: ChannelsOwnedRequest; res: ChannelsOwnedResponse };
|
||||
|
@ -147,6 +147,7 @@ export type BlockingListResponse = operations['blocking/list']['responses']['200
|
||||
export type ChannelsCreateRequest = operations['channels/create']['requestBody']['content']['application/json'];
|
||||
export type ChannelsCreateResponse = operations['channels/create']['responses']['200']['content']['application/json'];
|
||||
export type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
|
||||
export type ChannelsFeaturedGamesResponse = operations['channels/featured-games']['responses']['200']['content']['application/json'];
|
||||
export type ChannelsFollowRequest = operations['channels/follow']['requestBody']['content']['application/json'];
|
||||
export type ChannelsFollowedRequest = operations['channels/followed']['requestBody']['content']['application/json'];
|
||||
export type ChannelsFollowedResponse = operations['channels/followed']['responses']['200']['content']['application/json'];
|
||||
|
@ -918,6 +918,15 @@ export type paths = {
|
||||
*/
|
||||
post: operations['channels/featured'];
|
||||
};
|
||||
'/channels/featured-games': {
|
||||
/**
|
||||
* channels/featured-games
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *No*
|
||||
*/
|
||||
post: operations['channels/featured-games'];
|
||||
};
|
||||
'/channels/follow': {
|
||||
/**
|
||||
* channels/follow
|
||||
@ -4789,6 +4798,7 @@ export type operations = {
|
||||
perUserListTimelineCacheMax: number;
|
||||
notesPerOneAd: number;
|
||||
urlPreviewDenyList?: string[];
|
||||
featuredGameChannels: string[];
|
||||
backgroundImageUrl: string | null;
|
||||
deeplAuthKey: string | null;
|
||||
deeplIsPro: boolean;
|
||||
@ -8862,6 +8872,7 @@ export type operations = {
|
||||
silencedHosts?: string[] | null;
|
||||
sensitiveMediaHosts?: string[] | null;
|
||||
urlPreviewDenyList?: string[] | null;
|
||||
featuredGameChannels?: string[] | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -10677,6 +10688,52 @@ export type operations = {
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* channels/featured-games
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *No*
|
||||
*/
|
||||
'channels/featured-games': {
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Channel'][];
|
||||
};
|
||||
};
|
||||
/** @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'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* channels/follow
|
||||
* @description No description provided.
|
||||
|
Loading…
Reference in New Issue
Block a user