feat: Allow to chose webroot

issue #180
This commit is contained in:
C4illin 2024-11-06 08:49:53 +01:00
parent f3a4aece46
commit 36cb6cc589
7 changed files with 114 additions and 86 deletions

View file

@ -3,34 +3,37 @@ import { Html } from "@elysiajs/html";
export const BaseHtml = ({
children,
title = "ConvertX",
webroot = "",
}: {
children: JSX.Element;
title?: string;
webroot?: string;
}) => (
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="webroot" content={webroot} />
<title safe>{title}</title>
<link rel="stylesheet" href="/generated.css" />
<link rel="stylesheet" href={`${webroot}/generated.css`} />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/apple-touch-icon.png"
href={`${webroot}/apple-touch-icon.png`}
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon-32x32.png"
href={`${webroot}/favicon-32x32.png`}
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon-16x16.png"
href={`${webroot}/favicon-16x16.png`}
/>
<link rel="manifest" href="/site.webmanifest" />
<link rel="manifest" href={`${webroot}/site.webmanifest`} />
</head>
<body class="w-full bg-neutral-900 text-neutral-200">{children}</body>
</html>

View file

@ -3,9 +3,11 @@ import { Html } from "@kitajs/html";
export const Header = ({
loggedIn,
accountRegistration,
webroot = "",
}: {
loggedIn?: boolean;
accountRegistration?: boolean;
webroot?: string;
}) => {
let rightNav: JSX.Element;
if (loggedIn) {
@ -17,7 +19,7 @@ export const Header = ({
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href="/history"
href={`${webroot}/history`}
>
History
</a>
@ -28,7 +30,7 @@ export const Header = ({
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href="/logoff"
href={`${webroot}/logoff`}
>
Logout
</a>
@ -44,7 +46,7 @@ export const Header = ({
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href="/login"
href={`${webroot}/login`}
>
Login
</a>
@ -56,7 +58,7 @@ export const Header = ({
text-accent-600 transition-all
hover:text-accent-500 hover:underline
`}
href="/register"
href={`${webroot}/register`}
>
Register
</a>
@ -72,7 +74,7 @@ export const Header = ({
<ul>
<li>
<strong>
<a href="/">ConvertX</a>
<a href={`${webroot}/`}>ConvertX</a>
</strong>
</li>
</ul>

View file

@ -37,6 +37,8 @@ const AUTO_DELETE_EVERY_N_HOURS = process.env.AUTO_DELETE_EVERY_N_HOURS
? Number(process.env.AUTO_DELETE_EVERY_N_HOURS)
: 24;
const WEBROOT = process.env.WEBROOT ?? "/convertx";
// fileNames: fileNames,
// filesToConvert: fileNames.length,
// convertedFiles : 0,
@ -112,6 +114,7 @@ const app = new Elysia({
serve: {
maxRequestBodySize: Number.MAX_SAFE_INTEGER,
},
prefix: WEBROOT,
})
.use(cookie())
.use(html())
@ -145,18 +148,18 @@ const app = new Elysia({
})
.get("/setup", ({ redirect }) => {
if (!FIRST_RUN) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
return (
<BaseHtml title="ConvertX | Setup">
<BaseHtml title="ConvertX | Setup" webroot={WEBROOT}>
<main class="mx-auto w-full max-w-4xl px-4">
<h1 class="my-8 text-3xl">Welcome to ConvertX!</h1>
<article class="article p-0">
<header class="w-full bg-neutral-800 p-4">
Create your account
</header>
<form method="post" action="/register" class="p-4">
<form method="post" action={`${WEBROOT}/register`} class="p-4">
<fieldset class="mb-4 flex flex-col gap-4">
<label class="flex flex-col gap-1">
Email
@ -203,13 +206,16 @@ const app = new Elysia({
})
.get("/register", ({ redirect }) => {
if (!ACCOUNT_REGISTRATION) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
return (
<BaseHtml title="ConvertX | Register">
<BaseHtml webroot={WEBROOT} title="ConvertX | Register">
<>
<Header accountRegistration={ACCOUNT_REGISTRATION} />
<Header
webroot={WEBROOT}
accountRegistration={ACCOUNT_REGISTRATION}
/>
<main class="w-full px-4">
<article class="article">
<form method="post" class="flex flex-col gap-4">
@ -253,7 +259,7 @@ const app = new Elysia({
"/register",
async ({ body, set, redirect, jwt, cookie: { auth } }) => {
if (!ACCOUNT_REGISTRATION && !FIRST_RUN) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
if (FIRST_RUN) {
@ -308,13 +314,13 @@ const app = new Elysia({
sameSite: "strict",
});
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
},
{ body: t.Object({ email: t.String(), password: t.String() }) },
)
.get("/login", async ({ jwt, redirect, cookie: { auth } }) => {
if (FIRST_RUN) {
return redirect("/setup", 302);
return redirect(`${WEBROOT}/setup`, 302);
}
// if already logged in, redirect to home
@ -322,16 +328,19 @@ const app = new Elysia({
const user = await jwt.verify(auth.value);
if (user) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
auth.remove();
}
return (
<BaseHtml title="ConvertX | Login">
<BaseHtml webroot={WEBROOT} title="ConvertX | Login">
<>
<Header accountRegistration={ACCOUNT_REGISTRATION} />
<Header
webroot={WEBROOT}
accountRegistration={ACCOUNT_REGISTRATION}
/>
<main class="w-full px-4">
<article class="article">
<form method="post" class="flex flex-col gap-4">
@ -362,7 +371,7 @@ const app = new Elysia({
<div role="group">
{ACCOUNT_REGISTRATION ? (
<a
href="/register"
href={`${WEBROOT}/register`}
role="button"
class="btn-primary w-full"
>
@ -429,7 +438,7 @@ const app = new Elysia({
sameSite: "strict",
});
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
},
{ body: t.Object({ email: t.String(), password: t.String() }) },
)
@ -438,22 +447,22 @@ const app = new Elysia({
auth.remove();
}
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
})
.post("/logoff", ({ redirect, cookie: { auth } }) => {
if (auth?.value) {
auth.remove();
}
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
})
.get("/", async ({ jwt, redirect, cookie: { auth, jobId } }) => {
if (FIRST_RUN) {
return redirect("/setup", 302);
return redirect(`${WEBROOT}/setup`, 302);
}
if (!auth?.value && !ALLOW_UNAUTHENTICATED) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
// validate jwt
@ -473,7 +482,7 @@ const app = new Elysia({
if (auth?.value) {
auth.remove();
}
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
}
}
@ -506,7 +515,7 @@ const app = new Elysia({
}
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
// create a new job
@ -536,9 +545,9 @@ const app = new Elysia({
console.log("jobId set to:", id);
return (
<BaseHtml>
<BaseHtml webroot={WEBROOT}>
<>
<Header loggedIn />
<Header webroot={WEBROOT} loggedIn />
<main class="w-full px-4">
<article class="article">
<h1 class="mb-4 text-xl">Convert</h1>
@ -574,7 +583,7 @@ const app = new Elysia({
</article>
<form
method="post"
action="/convert"
action={`${WEBROOT}/convert`}
class="relative mx-auto mb-[35vh] w-full max-w-4xl"
>
<input type="hidden" name="file_names" id="file_names" />
@ -739,16 +748,16 @@ const app = new Elysia({
"/upload",
async ({ body, redirect, jwt, cookie: { auth, jobId } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
if (!jobId?.value) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
const existingJob = await db
@ -756,7 +765,7 @@ const app = new Elysia({
.get(jobId.value, user.id);
if (!existingJob) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
const userUploadsDir = `${uploadsDir}${user.id}/${jobId.value}/`;
@ -781,16 +790,16 @@ const app = new Elysia({
"/delete",
async ({ body, redirect, jwt, cookie: { auth, jobId } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
if (!jobId?.value) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
const existingJob = await db
@ -798,7 +807,7 @@ const app = new Elysia({
.get(jobId.value, user.id);
if (!existingJob) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
const userUploadsDir = `${uploadsDir}${user.id}/${jobId.value}/`;
@ -811,16 +820,16 @@ const app = new Elysia({
"/convert",
async ({ body, redirect, jwt, cookie: { auth, jobId } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
if (!jobId?.value) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
const existingJob = db
@ -829,7 +838,7 @@ const app = new Elysia({
.get(jobId.value, user.id);
if (!existingJob) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
const userUploadsDir = `${uploadsDir}${user.id}/${jobId.value}/`;
@ -850,7 +859,7 @@ const app = new Elysia({
const fileNames = JSON.parse(body.file_names) as string[];
if (!Array.isArray(fileNames) || fileNames.length === 0) {
return redirect("/", 302);
return redirect(`${WEBROOT}/`, 302);
}
db.query(
@ -903,7 +912,7 @@ const app = new Elysia({
});
// Redirect the client immediately
return redirect(`/results/${jobId.value}`, 302);
return redirect(`${WEBROOT}/results/${jobId.value}`, 302);
},
{
body: t.Object({
@ -914,12 +923,12 @@ const app = new Elysia({
)
.get("/history", async ({ jwt, redirect, cookie: { auth } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
let userJobs = db
@ -940,9 +949,9 @@ const app = new Elysia({
userJobs = userJobs.filter((job) => job.num_files > 0);
return (
<BaseHtml title="ConvertX | Results">
<BaseHtml webroot={WEBROOT} title="ConvertX | Results">
<>
<Header loggedIn />
<Header webroot={WEBROOT} loggedIn />
<main class="w-full px-4">
<article class="article">
<h1 class="mb-4 text-xl">Results</h1>
@ -975,7 +984,7 @@ const app = new Elysia({
text-accent-500 underline
hover:text-accent-400
`}
href={`/results/${job.id}`}
href={`${WEBROOT}/results/${job.id}`}
>
View
</a>
@ -994,7 +1003,7 @@ const app = new Elysia({
"/results/:jobId",
async ({ params, jwt, set, redirect, cookie: { auth, job_id } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
if (job_id?.value) {
@ -1004,7 +1013,7 @@ const app = new Elysia({
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const job = db
@ -1027,9 +1036,9 @@ const app = new Elysia({
.all(params.jobId);
return (
<BaseHtml title="ConvertX | Result">
<BaseHtml webroot={WEBROOT} title="ConvertX | Result">
<>
<Header loggedIn />
<Header webroot={WEBROOT} loggedIn />
<main class="w-full px-4">
<article class="article">
<div class="mb-4 flex items-center justify-between">
@ -1087,7 +1096,7 @@ const app = new Elysia({
text-accent-500 underline
hover:text-accent-400
`}
href={`/download/${outputPath}${file.output_file_name}`}
href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`}
>
View
</a>
@ -1098,7 +1107,7 @@ const app = new Elysia({
text-accent-500 underline
hover:text-accent-400
`}
href={`/download/${outputPath}${file.output_file_name}`}
href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`}
download={file.output_file_name}
>
Download
@ -1110,7 +1119,7 @@ const app = new Elysia({
</table>
</article>
</main>
<script src="/results.js" defer />
<script src={`${WEBROOT}/results.js`} defer />
</>
</BaseHtml>
);
@ -1120,7 +1129,7 @@ const app = new Elysia({
"/progress/:jobId",
async ({ jwt, set, params, redirect, cookie: { auth, job_id } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
if (job_id?.value) {
@ -1130,7 +1139,7 @@ const app = new Elysia({
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const job = db
@ -1209,7 +1218,7 @@ const app = new Elysia({
text-accent-500 underline
hover:text-accent-400
`}
href={`/download/${outputPath}${file.output_file_name}`}
href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`}
>
View
</a>
@ -1220,7 +1229,7 @@ const app = new Elysia({
text-accent-500 underline
hover:text-accent-400
`}
href={`/download/${outputPath}${file.output_file_name}`}
href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`}
download={file.output_file_name}
>
Download
@ -1238,12 +1247,12 @@ const app = new Elysia({
"/download/:userId/:jobId/:fileName",
async ({ params, jwt, redirect, cookie: { auth } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const job = await db
@ -1251,7 +1260,7 @@ const app = new Elysia({
.get(user.id, params.jobId);
if (!job) {
return redirect("/results", 302);
return redirect(`${WEBROOT}/results`, 302);
}
// parse from url encoded string
const userId = decodeURIComponent(params.userId);
@ -1264,18 +1273,18 @@ const app = new Elysia({
)
.get("/converters", async ({ jwt, redirect, cookie: { auth } }) => {
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
return (
<BaseHtml title="ConvertX | Converters">
<BaseHtml webroot={WEBROOT} title="ConvertX | Converters">
<>
<Header loggedIn />
<Header webroot={WEBROOT} loggedIn />
<main class="w-full px-4">
<article class="article">
<h1 class="mb-4 text-xl">Converters</h1>
@ -1334,12 +1343,12 @@ const app = new Elysia({
async ({ params, jwt, redirect, cookie: { auth } }) => {
// TODO: Implement zip download
if (!auth?.value) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const user = await jwt.verify(auth.value);
if (!user) {
return redirect("/login", 302);
return redirect(`${WEBROOT}/login`, 302);
}
const job = await db
@ -1347,12 +1356,12 @@ const app = new Elysia({
.get(user.id, params.jobId);
if (!job) {
return redirect("/results", 302);
return redirect(`${WEBROOT}/results`, 302);
}
// const userId = decodeURIComponent(params.userId);
// const jobId = decodeURIComponent(params.jobId);
// const outputPath = `${outputDir}${userId}/${jobId}/`;
// const outputPath = `${outputDir}${userId}/`{jobId}/);
// return Bun.zip(outputPath);
},
@ -1376,7 +1385,7 @@ if (process.env.NODE_ENV !== "production") {
app.listen(3000);
console.log(
`🦊 Elysia is running at http://${app.server?.hostname}:${app.server?.port}`,
`🦊 Elysia is running at http://${app.server?.hostname}:${app.server?.port}${WEBROOT}`,
);
const clearJobs = () => {