diff --git a/express/backend/src/api/weblate-proxy.ts b/express/backend/src/api/weblate-proxy.ts index 723337c..aa6c5a7 100644 --- a/express/backend/src/api/weblate-proxy.ts +++ b/express/backend/src/api/weblate-proxy.ts @@ -2,19 +2,31 @@ import axios from "axios"; import { Router } from "express"; import { env } from "../common"; +const WEBLATE_API = "https://weblate.iobroker.net/api/"; +const ALLOWED_PATHS = ["projects/adapters/components/"] as const; + const router = Router(); router.get<any>("/api/weblate/*", async function (req, res) { try { - const result = await axios.get<any>( - `https://weblate.iobroker.net/api/${req.params["0"]}`, - { - headers: { - accept: "application/json", - authorization: `Token ${env.WEBLATE_ACCESS_TOKEN}`, - }, + const userPath = req.params["0"]; + if (!ALLOWED_PATHS.some((path) => userPath.startsWith(path))) { + return res.status(400).send("Invalid path"); + } + const url = new URL(`${WEBLATE_API}${userPath}`); + const q = req.query; + if (q.page) { + url.searchParams.set("page", Number(q.page).toString()); + } + + const result = await axios.get<any>(url.toString(), { + headers: { + accept: "application/json", + authorization: `Token ${env.WEBLATE_ACCESS_TOKEN}`, }, - ); + }); + result.data.previous = convertLink(result.data.previous); + result.data.next = convertLink(result.data.next); res.send(result.data); } catch (error: any) { console.error(error); @@ -22,4 +34,11 @@ router.get<any>("/api/weblate/*", async function (req, res) { } }); +function convertLink(link: string | null): string | null { + if (!link) { + return null; + } + return link.replace(WEBLATE_API, "/api/weblate/"); +} + export default router; diff --git a/express/frontend/src/components/dashboard/Dashboard.tsx b/express/frontend/src/components/dashboard/Dashboard.tsx index 2c37957..c6fb511 100644 --- a/express/frontend/src/components/dashboard/Dashboard.tsx +++ b/express/frontend/src/components/dashboard/Dashboard.tsx @@ -262,9 +262,7 @@ async function getDiscoveryLink(adapterName: string) { async function getWeblateLink(adapterName: string) { try { const components = await getWeblateAdapterComponents(); - const component = components.results.find( - (c: any) => c.name === adapterName, - ); + const component = components.find((c: any) => c.name === adapterName); if (component) { return ( `https://weblate.iobroker.net/projects/adapters/` + diff --git a/express/frontend/src/lib/ioBroker.ts b/express/frontend/src/lib/ioBroker.ts index e75a701..54b78a6 100644 --- a/express/frontend/src/lib/ioBroker.ts +++ b/express/frontend/src/lib/ioBroker.ts @@ -169,10 +169,15 @@ export async function getAdapterInfos( } export const getWeblateAdapterComponents = AsyncCache.of(async () => { - const result = await axios.get<any>( - getApiUrl("weblate/projects/adapters/components/"), - ); - return result.data; + const components: any[] = []; + let url = "weblate/projects/adapters/components/"; + do { + const result = await axios.get<any>(getApiUrl(url)); + components.push(...result.data.results); + url = result.data.next?.replace("/api/", ""); + } while (url); + + return components; }); export async function getStatistics(adapterName: string) {