mirror of
https://github.com/skidoodle/erettsegi-browser.git
synced 2026-04-27 21:17:36 +02:00
app router
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": true
|
||||
}
|
||||
+4
-3
@@ -1,16 +1,17 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
||||
"vcs": {
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": false
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": false
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "tab"
|
||||
"indentStyle": "tab",
|
||||
"lineWidth": 80
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
|
||||
@@ -4,4 +4,4 @@ const config = {
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
export default config;
|
||||
@@ -0,0 +1,120 @@
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { subjects } from "@/utils/subjects";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = req.nextUrl;
|
||||
const vizsgatargy = searchParams.get("vizsgatargy");
|
||||
const ev = searchParams.get("ev");
|
||||
const idoszak = searchParams.get("idoszak");
|
||||
const szint = searchParams.get("szint");
|
||||
|
||||
if (!vizsgatargy || !ev || !idoszak || !szint) {
|
||||
const missingParams = [];
|
||||
if (!vizsgatargy) missingParams.push("vizsgatargy");
|
||||
if (!ev) missingParams.push("ev");
|
||||
if (!idoszak) missingParams.push("idoszak");
|
||||
if (!szint) missingParams.push("szint");
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: `Hiányzó paraméterek: ${missingParams.join(", ")}` },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
if (parseInt(ev, 10) <= 2012) {
|
||||
return NextResponse.json({ error: "Érvénytelen év" }, { status: 400 });
|
||||
}
|
||||
|
||||
const validSubjects = subjects.map((subject) => subject.value);
|
||||
if (!validSubjects.includes(vizsgatargy)) {
|
||||
return NextResponse.json(
|
||||
{ error: "Érvénytelen vizsgatárgy" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
let honap: string;
|
||||
switch (idoszak) {
|
||||
case "osz":
|
||||
honap = "okt";
|
||||
break;
|
||||
case "tavasz":
|
||||
honap = "maj";
|
||||
break;
|
||||
default:
|
||||
return NextResponse.json(
|
||||
{ error: "Érvénytelen időszak" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
let prefix: string;
|
||||
switch (szint) {
|
||||
case "emelt":
|
||||
prefix = `e_${vizsgatargy}`;
|
||||
break;
|
||||
case "kozep":
|
||||
prefix = `k_${vizsgatargy}`;
|
||||
break;
|
||||
default:
|
||||
return NextResponse.json(
|
||||
{ error: "Érvénytelen szint" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const protocol =
|
||||
req.headers.get("x-forwarded-proto") === "https" ? "https" : "http";
|
||||
const host = req.headers.get("host");
|
||||
const baseUrl = `https://dload-oktatas.educatio.hu/erettsegi/feladatok_${ev}${idoszak}_${szint}/`;
|
||||
const proxiedUrl = `${protocol}://${host}/api/proxy?link=${encodeURI(baseUrl)}`;
|
||||
|
||||
const shortev = ev.slice(-2);
|
||||
const feladat = "fl";
|
||||
const utmutato = "ut";
|
||||
const forras = "for";
|
||||
const megoldas = "meg";
|
||||
|
||||
let flPdfUrl: string | undefined,
|
||||
utPdfUrl: string | undefined,
|
||||
flZipUrl: string | undefined,
|
||||
utZipUrl: string | undefined,
|
||||
flMp3Url: string | undefined;
|
||||
|
||||
switch (vizsgatargy) {
|
||||
case "inf":
|
||||
case "infoism":
|
||||
case "digkult":
|
||||
flZipUrl = `${baseUrl}${prefix}${forras}_${shortev}${honap}_${feladat}.zip`;
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utZipUrl = `${baseUrl}${prefix}${megoldas}_${shortev}${honap}_${utmutato}.zip`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
break;
|
||||
case "angol":
|
||||
case "nemet":
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
flMp3Url = `${baseUrl}${prefix}_${shortev}${honap}_${feladat}.mp3`;
|
||||
break;
|
||||
default:
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
break;
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ flPdfUrl, utPdfUrl, flZipUrl, utZipUrl, flMp3Url },
|
||||
{
|
||||
status: 200,
|
||||
headers: { "Cache-Control": "s-maxage=31536000" },
|
||||
},
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
console.error("An unexpected error occurred in the API route:", e);
|
||||
return NextResponse.json(
|
||||
{ error: "Internal Server Error" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { Agent, fetch } from "undici";
|
||||
|
||||
const insecureAgent = new Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
});
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = req.nextUrl;
|
||||
const link = searchParams.get("link");
|
||||
|
||||
if (!link) {
|
||||
return NextResponse.json(
|
||||
{ error: "Hiányzó paraméter: link" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(link);
|
||||
} catch (_error) {
|
||||
return NextResponse.json(
|
||||
{ error: "Érvénytelen link formátum" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
if (url.hostname !== "dload-oktatas.educatio.hu") {
|
||||
return NextResponse.json({ error: "Érvénytelen link" }, { status: 400 });
|
||||
}
|
||||
|
||||
const externalResponse = await fetch(link, {
|
||||
method: "GET",
|
||||
dispatcher: insecureAgent,
|
||||
});
|
||||
|
||||
if (!externalResponse.ok) {
|
||||
return NextResponse.json(
|
||||
{ error: "Hiba történt a külső forrás lekérése során." },
|
||||
{ status: externalResponse.status },
|
||||
);
|
||||
}
|
||||
|
||||
const body = await externalResponse.arrayBuffer();
|
||||
|
||||
const contentType = externalResponse.headers.get("content-type");
|
||||
const headers = new Headers();
|
||||
headers.set("Cache-Control", "s-maxage=31536000, stale-while-revalidate");
|
||||
|
||||
if (contentType) {
|
||||
headers.set("Content-Type", contentType);
|
||||
if (contentType === "application/pdf") {
|
||||
const filename = url.pathname.split("/").pop() ?? "document.pdf";
|
||||
headers.set("Content-Disposition", `inline; filename="${filename}"`);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(body, {
|
||||
status: 200,
|
||||
headers: headers,
|
||||
});
|
||||
} catch (e: unknown) {
|
||||
console.error("Proxy Error:", e);
|
||||
if (e instanceof Error) {
|
||||
return NextResponse.json(
|
||||
{ error: "Internal Server Error", message: e.message },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ error: "An unexpected internal error occurred" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { Agent, fetch } from "undici";
|
||||
|
||||
const insecureAgent = new Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
});
|
||||
|
||||
const ALLOWED_HOSTS = [
|
||||
"localhost:3000",
|
||||
"erettsegi.albert.lol",
|
||||
"dload-oktatas.educatio.hu",
|
||||
];
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = req.nextUrl;
|
||||
const link = searchParams.get("link");
|
||||
|
||||
if (!link) {
|
||||
return NextResponse.json(
|
||||
{ error: "Hiányzó paraméter: link" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(link);
|
||||
} catch (_error) {
|
||||
return NextResponse.json(
|
||||
{ error: "Érvénytelen link formátum" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
if (!ALLOWED_HOSTS.includes(url.host)) {
|
||||
return NextResponse.json({ error: "Érvénytelen link" }, { status: 400 });
|
||||
}
|
||||
|
||||
const response = await fetch(link, {
|
||||
method: "HEAD",
|
||||
dispatcher: insecureAgent,
|
||||
});
|
||||
|
||||
return NextResponse.json({ status: response.status }, { status: 200 });
|
||||
} catch (e: unknown) {
|
||||
console.error("Validation Error:", e);
|
||||
|
||||
if (e instanceof Error) {
|
||||
const cause = e.cause as { code?: unknown } | undefined;
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Internal Server Error",
|
||||
message: e.message,
|
||||
cause: cause?.code ? String(cause.code) : undefined,
|
||||
stack: process.env.NODE_ENV === "development" ? e.stack : undefined,
|
||||
},
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Internal Server Error",
|
||||
message: "An unexpected error occurred",
|
||||
details: String(e),
|
||||
},
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import Script from "next/script";
|
||||
import { Providers } from "@/app/providers";
|
||||
import { Inter } from "next/font/google";
|
||||
import "@/styles/globals.css";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-inter",
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL("https://erettsegi.albert.lol"),
|
||||
title: "Érettségi kereső",
|
||||
description: "Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫",
|
||||
icons: {
|
||||
icon: "/favicon.ico",
|
||||
},
|
||||
openGraph: {
|
||||
title: "Érettségi kereső",
|
||||
description:
|
||||
"Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫",
|
||||
url: "https://erettsegi.albert.lol",
|
||||
images: "/logo.png",
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#121212",
|
||||
width: "device-width",
|
||||
initialScale: 1,
|
||||
maximumScale: 1,
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="hu" suppressHydrationWarning>
|
||||
<Script
|
||||
defer
|
||||
src="https://analytics.albert.lol/script.js"
|
||||
data-website-id="7b196f47-39c9-4b8e-8dfd-b6e707282eea"
|
||||
/>
|
||||
<body className={`${inter.variable} antialiased font-sans`}>
|
||||
<Providers>{children}</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import { useRouter } from "next/router";
|
||||
import { Footer } from "@/components/Footer";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function ErrorPage() {
|
||||
const router = useRouter();
|
||||
|
||||
const handleBack = () => {
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<>
|
||||
<main className="dark:bg-[#121212] text-foreground bg-background py-5">
|
||||
@@ -22,9 +18,9 @@ export default function ErrorPage() {
|
||||
<div className="text-2xl font-semibold text-gray-600">
|
||||
<p className="mt-2">Az keresett oldal nem található.</p>
|
||||
<p className="mt-8 text-center">
|
||||
<Button color="primary" onPress={handleBack}>
|
||||
Vissza
|
||||
</Button>
|
||||
<Link href="/">
|
||||
<Button color="primary">Vissza</Button>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { ButtonGroup, Divider } from "@heroui/react";
|
||||
import { useEffect } from "react";
|
||||
import { Mp3Button, PdfButton, ZipButton } from "@/components/Buttons";
|
||||
@@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { HeroUIProvider } from "@heroui/react";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
|
||||
export function Providers({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<HeroUIProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem={true}>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</HeroUIProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import type { ButtonProps } from "@/utils/props";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { Source } from "@/components/Source";
|
||||
import { ThemeSwitcher } from "@/components/ThemeSwitcher";
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { Select, SelectItem } from "@heroui/react";
|
||||
import type { SelectorProps } from "@/utils/props";
|
||||
import type { ChangeEvent } from "react";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import { VscGithubInverted } from "react-icons/vsc";
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import { useTheme } from "next-themes";
|
||||
import { VscColorMode } from "react-icons/vsc";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import useYears from "@/hooks/useYears";
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function useYears(
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { HeroUIProvider } from "@heroui/react";
|
||||
import type { AppProps } from "next/app";
|
||||
import { Inter } from "next/font/google";
|
||||
import Head from "next/head";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import "@/styles/globals.css";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-inter",
|
||||
});
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Érettségi kereső</title>
|
||||
</Head>
|
||||
<HeroUIProvider className={`${inter.variable} font-sans`}>
|
||||
<NextThemesProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem={true}
|
||||
>
|
||||
<Component {...pageProps} />
|
||||
</NextThemesProvider>
|
||||
</HeroUIProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Head, Html, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="hu">
|
||||
<Head>
|
||||
<meta name="theme-color" content="#121212" />
|
||||
<meta name="title" content="Érettségi kereső" />
|
||||
<meta name="og:title" content="Érettségi kereső" />
|
||||
<meta property="og:url" content="https://erettsegi.albert.lol" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫"
|
||||
/>
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Egyszerű keresés és letöltés az érettségi feladatsorokhoz. 🏫"
|
||||
/>
|
||||
<script
|
||||
defer
|
||||
src="https://analytics.albert.lol/script.js"
|
||||
data-website-id="7b196f47-39c9-4b8e-8dfd-b6e707282eea"
|
||||
></script>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta property="image" content="/logo.png" />
|
||||
<meta property="og:image" content="/logo.png" />
|
||||
<meta name="author" content="albert" />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { subjects } from "@/utils/subjects";
|
||||
|
||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { vizsgatargy, ev, idoszak, szint } = req.query as {
|
||||
vizsgatargy: string;
|
||||
ev: string;
|
||||
idoszak: string;
|
||||
szint: string;
|
||||
};
|
||||
|
||||
const secure = req.headers["x-forwarded-proto"] === "https";
|
||||
const protocol = secure ? "https" : "http";
|
||||
const address = req.headers.host;
|
||||
|
||||
const baseUrl = `https://dload-oktatas.educatio.hu/erettsegi/feladatok_${ev}${idoszak}_${szint}/`;
|
||||
const proxiedUrl = `${protocol}://${address}/api/proxy?link=${encodeURI(
|
||||
baseUrl,
|
||||
)}`;
|
||||
|
||||
const missingParams = [];
|
||||
if (!ev) missingParams.push("ev");
|
||||
if (!szint) missingParams.push("szint");
|
||||
if (!idoszak) missingParams.push("idoszak");
|
||||
if (!vizsgatargy) missingParams.push("vizsgatargy");
|
||||
|
||||
if (missingParams.length > 0) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Hiányzó paraméterek: ${missingParams.join(", ")}` });
|
||||
}
|
||||
|
||||
if (ev <= "2012") {
|
||||
return res.status(400).json({ error: "Érvénytelen év" });
|
||||
}
|
||||
|
||||
const validSubjects = subjects.map((subject) => subject.value);
|
||||
if (!vizsgatargy || !validSubjects.includes(vizsgatargy)) {
|
||||
return res.status(400).json({ error: "Érvénytelen vizsgatárgy" });
|
||||
}
|
||||
|
||||
let honap: string;
|
||||
switch (idoszak) {
|
||||
case "osz":
|
||||
honap = "okt";
|
||||
break;
|
||||
case "tavasz":
|
||||
honap = "maj";
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ error: "Érvénytelen időszak" });
|
||||
}
|
||||
|
||||
let prefix: string;
|
||||
switch (szint) {
|
||||
case "emelt":
|
||||
prefix = `e_${vizsgatargy}`;
|
||||
break;
|
||||
case "kozep":
|
||||
prefix = `k_${vizsgatargy}`;
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ error: "Érvénytelen szint" });
|
||||
}
|
||||
|
||||
const feladat = "fl";
|
||||
const utmutato = "ut";
|
||||
const forras = "for";
|
||||
const megoldas = "meg";
|
||||
const shortev = ev.slice(-2);
|
||||
|
||||
let flPdfUrl: string | undefined,
|
||||
utPdfUrl: string | undefined,
|
||||
flZipUrl: string | undefined,
|
||||
utZipUrl: string | undefined,
|
||||
flMp3Url: string | undefined;
|
||||
switch (vizsgatargy) {
|
||||
case "inf":
|
||||
case "infoism":
|
||||
case "digkult":
|
||||
flZipUrl = `${baseUrl}${prefix}${forras}_${shortev}${honap}_${feladat}.zip`;
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utZipUrl = `${baseUrl}${prefix}${megoldas}_${shortev}${honap}_${utmutato}.zip`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
break;
|
||||
case "angol":
|
||||
case "nemet":
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
flMp3Url = `${baseUrl}${prefix}_${shortev}${honap}_${feladat}.mp3`;
|
||||
break;
|
||||
default:
|
||||
flPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`;
|
||||
utPdfUrl = `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`;
|
||||
break;
|
||||
}
|
||||
|
||||
res.setHeader("Cache-Control", "s-maxage=31536000");
|
||||
res.status(200).json({ flPdfUrl, utPdfUrl, flZipUrl, utZipUrl, flMp3Url });
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
let causeCode: string | undefined;
|
||||
if (e.cause && typeof e.cause === "object" && "code" in e.cause) {
|
||||
causeCode = String((e.cause as { code: unknown }).code);
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: e.message,
|
||||
cause: causeCode,
|
||||
stack: process.env.NODE_ENV === "development" ? e.stack : undefined,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: "An unexpected error occurred",
|
||||
details: String(e),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { Agent, fetch } from "undici";
|
||||
|
||||
const insecureAgent = new Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
const { link } = req.query as { link: string };
|
||||
let missingParam: string | null = null;
|
||||
if (!link) {
|
||||
missingParam = "link";
|
||||
}
|
||||
|
||||
if (missingParam) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Hiányzó paraméter: ${missingParam}` });
|
||||
}
|
||||
|
||||
const domain = link.split("/")[2];
|
||||
if (domain !== "dload-oktatas.educatio.hu") {
|
||||
return res.status(400).json({ error: "Érvénytelen link" });
|
||||
}
|
||||
|
||||
try {
|
||||
res.setHeader("Cache-Control", "s-maxage=31536000");
|
||||
|
||||
const response = await fetch(link, {
|
||||
method: "GET",
|
||||
dispatcher: insecureAgent,
|
||||
});
|
||||
|
||||
const contentType = response.headers.get("content-type");
|
||||
|
||||
if (contentType === "application/pdf") {
|
||||
const filename = link.split("/").pop() ?? "document.pdf";
|
||||
res.setHeader("Content-Type", contentType);
|
||||
res.setHeader("Content-Disposition", `inline; filename="${filename}"`);
|
||||
}
|
||||
|
||||
if (response.ok) {
|
||||
const arrayBuffer: ArrayBuffer = await response.arrayBuffer();
|
||||
const buffer: Buffer = Buffer.from(arrayBuffer);
|
||||
res.send(buffer);
|
||||
} else {
|
||||
res
|
||||
.status(response.status)
|
||||
.json({ error: "Hiba történt a lekérés során." });
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
let causeCode: string | undefined;
|
||||
if (e.cause && typeof e.cause === "object" && "code" in e.cause) {
|
||||
causeCode = String((e.cause as { code: unknown }).code);
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: e.message,
|
||||
cause: causeCode,
|
||||
stack: process.env.NODE_ENV === "development" ? e.stack : undefined,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: "An unexpected error occurred",
|
||||
details: String(e),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { Agent, fetch } from "undici";
|
||||
|
||||
const insecureAgent = new Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
const { link } = req.query as { link: string };
|
||||
let missingParam: string | null = null;
|
||||
|
||||
if (!link) {
|
||||
missingParam = "link";
|
||||
}
|
||||
|
||||
if (missingParam) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Hiányzó paraméter: ${missingParam}` });
|
||||
}
|
||||
|
||||
const domain = link.split("/")[2];
|
||||
if (
|
||||
domain !== "localhost:3000" &&
|
||||
domain !== "erettsegi.albert.lol" &&
|
||||
domain !== "dload-oktatas.educatio.hu"
|
||||
) {
|
||||
return res.status(400).json({ error: "Érvénytelen link" });
|
||||
}
|
||||
|
||||
try {
|
||||
const { protocol, host } = new URL(link);
|
||||
if (!protocol || !host) {
|
||||
return res.status(400).json({ error: "Érvénytelen link" });
|
||||
}
|
||||
|
||||
const response = await fetch(link, {
|
||||
method: "HEAD",
|
||||
dispatcher: insecureAgent,
|
||||
});
|
||||
|
||||
const status = response.status;
|
||||
res.status(200).json({ status });
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
let causeCode: string | undefined;
|
||||
if (e.cause && typeof e.cause === "object" && "code" in e.cause) {
|
||||
causeCode = String((e.cause as { code: unknown }).code);
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: e.message,
|
||||
cause: causeCode,
|
||||
stack: process.env.NODE_ENV === "development" ? e.stack : undefined,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
error: "Internal Server Error",
|
||||
message: "An unexpected error occurred",
|
||||
details: String(e),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
-26
@@ -1,27 +1,36 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Base Options: */
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"target": "es2022",
|
||||
/* Basic Options */
|
||||
"target": "esnext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleDetection": "force",
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
|
||||
/* Strictness */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"checkJs": true,
|
||||
|
||||
/* Bundled projects */
|
||||
"lib": ["dom", "dom.iterable", "ES2022"],
|
||||
/* Module Resolution */
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
|
||||
/* Code Style */
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"jsx": "preserve",
|
||||
"plugins": [{ "name": "next" }],
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
|
||||
/* Path Aliases */
|
||||
"baseUrl": ".",
|
||||
@@ -29,16 +38,6 @@
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
".eslintrc.cjs",
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.cjs",
|
||||
"**/*.js",
|
||||
".next/types/**/*.ts",
|
||||
"next.config.mjs",
|
||||
"postcss.config.mjs"
|
||||
],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user