From 2ff90a80d453e33caee2cc39f27149d1d7386ee1 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:36:01 +0900 Subject: [PATCH] fix(backend): add detailed schema to `fetch-rss` endpoint (#13764) --- .../src/server/api/endpoints/fetch-rss.ts | 179 +++++++++++++++++- .../src/ui/_common_/statusbar-rss.vue | 5 +- packages/frontend/src/widgets/WidgetRss.vue | 7 +- .../frontend/src/widgets/WidgetRssTicker.vue | 7 +- packages/misskey-js/src/autogen/types.ts | 47 ++++- 5 files changed, 234 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts index 2085b06365..ba48b0119e 100644 --- a/packages/backend/src/server/api/endpoints/fetch-rss.ts +++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts @@ -20,13 +20,188 @@ export const meta = { res: { type: 'object', properties: { + image: { + type: 'object', + optional: true, + properties: { + link: { + type: 'string', + optional: true, + }, + url: { + type: 'string', + optional: false, + }, + title: { + type: 'string', + optional: true, + }, + }, + }, + paginationLinks: { + type: 'object', + optional: true, + properties: { + self: { + type: 'string', + optional: true, + }, + first: { + type: 'string', + optional: true, + }, + next: { + type: 'string', + optional: true, + }, + last: { + type: 'string', + optional: true, + }, + prev: { + type: 'string', + optional: true, + }, + }, + }, + link: { + type: 'string', + optional: true, + }, + title: { + type: 'string', + optional: true, + }, items: { type: 'array', + optional: false, items: { type: 'object', + properties: { + link: { + type: 'string', + optional: true, + }, + guid: { + type: 'string', + optional: true, + }, + title: { + type: 'string', + optional: true, + }, + pubDate: { + type: 'string', + optional: true, + }, + creator: { + type: 'string', + optional: true, + }, + summary: { + type: 'string', + optional: true, + }, + content: { + type: 'string', + optional: true, + }, + isoDate: { + type: 'string', + optional: true, + }, + categories: { + type: 'array', + optional: true, + items: { + type: 'string', + }, + }, + contentSnippet: { + type: 'string', + optional: true, + }, + enclosure: { + type: 'object', + optional: true, + properties: { + url: { + type: 'string', + optional: false, + }, + length: { + type: 'number', + optional: true, + }, + type: { + type: 'string', + optional: true, + }, + }, + }, + }, }, - } - } + }, + feedUrl: { + type: 'string', + optional: true, + }, + description: { + type: 'string', + optional: true, + }, + itunes: { + type: 'object', + optional: true, + additionalProperties: true, + properties: { + image: { + type: 'string', + optional: true, + }, + owner: { + type: 'object', + optional: true, + properties: { + name: { + type: 'string', + optional: true, + }, + email: { + type: 'string', + optional: true, + }, + }, + }, + author: { + type: 'string', + optional: true, + }, + summary: { + type: 'string', + optional: true, + }, + explicit: { + type: 'string', + optional: true, + }, + categories: { + type: 'array', + optional: true, + items: { + type: 'string', + }, + }, + keywords: { + type: 'array', + optional: true, + items: { + type: 'string', + }, + }, + }, + }, + }, }, } as const; diff --git a/packages/frontend/src/ui/_common_/statusbar-rss.vue b/packages/frontend/src/ui/_common_/statusbar-rss.vue index b973a4fd6b..6e1d06eec1 100644 --- a/packages/frontend/src/ui/_common_/statusbar-rss.vue +++ b/packages/frontend/src/ui/_common_/statusbar-rss.vue @@ -28,6 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; +import * as Misskey from 'misskey-js'; import MarqueeText from '@/components/MkMarquee.vue'; import { useInterval } from '@/scripts/use-interval.js'; import { shuffle } from '@/scripts/shuffle.js'; @@ -42,13 +43,13 @@ const props = defineProps<{ refreshIntervalSec?: number; }>(); -const items = ref([]); +const items = ref<Misskey.entities.FetchRssResponse['items']>([]); const fetching = ref(true); const key = ref(0); const tick = () => { window.fetch(`/api/fetch-rss?url=${props.url}`, {}).then(res => { - res.json().then(feed => { + res.json().then((feed: Misskey.entities.FetchRssResponse) => { if (props.shuffle) { shuffle(feed.items); } diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue index 5d5c1188aa..e5758662cc 100644 --- a/packages/frontend/src/widgets/WidgetRss.vue +++ b/packages/frontend/src/widgets/WidgetRss.vue @@ -24,6 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch, computed } from 'vue'; +import * as Misskey from 'misskey-js'; import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; @@ -64,7 +65,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); -const rawItems = ref([]); +const rawItems = ref<Misskey.entities.FetchRssResponse['items']>([]); const items = computed(() => rawItems.value.slice(0, widgetProps.maxEntries)); const fetching = ref(true); const fetchEndpoint = computed(() => { @@ -79,8 +80,8 @@ const tick = () => { window.fetch(fetchEndpoint.value, {}) .then(res => res.json()) - .then(feed => { - rawItems.value = feed.items ?? []; + .then((feed: Misskey.entities.FetchRssResponse) => { + rawItems.value = feed.items; fetching.value = false; }); }; diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue index af220f95e2..16306ef5ba 100644 --- a/packages/frontend/src/widgets/WidgetRssTicker.vue +++ b/packages/frontend/src/widgets/WidgetRssTicker.vue @@ -28,6 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch, computed } from 'vue'; +import * as Misskey from 'misskey-js'; import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import MarqueeText from '@/components/MkMarquee.vue'; import { GetFormResultType } from '@/scripts/form.js'; @@ -87,7 +88,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); -const rawItems = ref([]); +const rawItems = ref<Misskey.entities.FetchRssResponse['items']>([]); const items = computed(() => { const newItems = rawItems.value.slice(0, widgetProps.maxEntries); if (widgetProps.shuffle) { @@ -110,8 +111,8 @@ const tick = () => { window.fetch(fetchEndpoint.value, {}) .then(res => res.json()) - .then(feed => { - rawItems.value = feed.items ?? []; + .then((feed: Misskey.entities.FetchRssResponse) => { + rawItems.value = feed.items; fetching.value = false; key.value++; }); diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 131d20f09b..1b9f1304d5 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -26065,7 +26065,52 @@ export type operations = { 200: { content: { 'application/json': { - items: Record<string, never>[]; + image?: { + link?: string; + url: string; + title?: string; + }; + paginationLinks?: { + self?: string; + first?: string; + next?: string; + last?: string; + prev?: string; + }; + link?: string; + title?: string; + items: { + link?: string; + guid?: string; + title?: string; + pubDate?: string; + creator?: string; + summary?: string; + content?: string; + isoDate?: string; + categories?: string[]; + contentSnippet?: string; + enclosure?: { + url: string; + length?: number; + type?: string; + }; + }[]; + feedUrl?: string; + description?: string; + itunes?: { + image?: string; + owner?: { + name?: string; + email?: string; + }; + author?: string; + summary?: string; + explicit?: string; + categories?: string[]; + keywords?: string[]; + [key: string]: unknown; + }; }; }; };