Update button styling and render additional elements on file page if authenticated
This commit is contained in:
@@ -119,9 +119,16 @@ export const pageRoutes: FastifyPluginAsync<{ deps: Deps }> = async (app, { deps
|
||||
reply.redirect('/files');
|
||||
});
|
||||
|
||||
// GET /f/:id — public file view
|
||||
// GET /f/:id — public file view (owner-aware)
|
||||
app.get<{ Params: { id: string } }>('/f/:id', async (request, reply) => {
|
||||
const { id } = request.params;
|
||||
|
||||
let userId: number | null = null;
|
||||
try {
|
||||
await request.jwtVerify();
|
||||
userId = (request.user as JwtPayload).sub;
|
||||
} catch { /* not logged in — fine */ }
|
||||
|
||||
const file = getFileById(db, id);
|
||||
|
||||
if (!file) {
|
||||
@@ -129,7 +136,8 @@ export const pageRoutes: FastifyPluginAsync<{ deps: Deps }> = async (app, { deps
|
||||
return reply.status(404).type('text/html').send(notFoundPage());
|
||||
}
|
||||
|
||||
reply.type('text/html').send(fileViewPage(file));
|
||||
const isOwner = userId !== null && userId === file.user_id;
|
||||
reply.type('text/html').send(fileViewPage(file, isOwner));
|
||||
});
|
||||
|
||||
// GET /f/:id/raw — serve raw file
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { layout, escHtml } from './layout.ts';
|
||||
import type { FileRow } from '../db/files.ts';
|
||||
|
||||
export function fileViewPage(file: FileRow): string {
|
||||
export function fileViewPage(file: FileRow, isOwner: boolean): string {
|
||||
const rawUrl = escHtml(`/f/${file.id}/raw`);
|
||||
const safeName = escHtml(file.original_name);
|
||||
const actions = `
|
||||
@@ -10,6 +10,12 @@ export function fileViewPage(file: FileRow): string {
|
||||
<a href="${rawUrl}" target="_blank" class="btn">Open</a>
|
||||
</div>`;
|
||||
|
||||
const deleteForm = isOwner
|
||||
? `<form method="POST" action="/files/${escHtml(file.id)}/delete">
|
||||
<button type="submit" class="danger">Delete</button>
|
||||
</form>`
|
||||
: '';
|
||||
|
||||
let media = '';
|
||||
if (file.mime_type.startsWith('image/')) {
|
||||
media = `<img src="${rawUrl}" alt="${safeName}">`;
|
||||
@@ -19,11 +25,14 @@ export function fileViewPage(file: FileRow): string {
|
||||
media = `<audio controls src="${rawUrl}" preload="metadata"></audio>`;
|
||||
}
|
||||
|
||||
const layoutOpts = isOwner ? { authed: true } : { hideHeader: true };
|
||||
|
||||
return layout(file.original_name, `
|
||||
<div class="file-view">
|
||||
<h1>${safeName}</h1>
|
||||
${media}
|
||||
${actions}
|
||||
${deleteForm}
|
||||
</div>
|
||||
`, { hideLogo: true });
|
||||
`, layoutOpts);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export function layout(title: string, body: string, opts: { authed?: boolean; hideLogo?: boolean } = {}): string {
|
||||
const { authed = false, hideLogo = false } = opts;
|
||||
export function layout(title: string, body: string, opts: { authed?: boolean; hideHeader?: boolean } = {}): string {
|
||||
const { authed = false, hideHeader = false } = opts;
|
||||
const nav = authed
|
||||
? `<nav>
|
||||
<a href="/upload">Upload</a>
|
||||
@@ -10,6 +10,13 @@ export function layout(title: string, body: string, opts: { authed?: boolean; hi
|
||||
</nav>`
|
||||
: '';
|
||||
|
||||
const header = hideHeader
|
||||
? ''
|
||||
: ` <header>
|
||||
<a href="/" class="logo">Nanodrop</a>
|
||||
${nav}
|
||||
</header>`;
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -19,10 +26,7 @@ export function layout(title: string, body: string, opts: { authed?: boolean; hi
|
||||
<link rel="stylesheet" href="/public/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
${hideLogo ? '' : '<a href="/" class="logo">Nanodrop</a>'}
|
||||
${nav}
|
||||
</header>
|
||||
${header}
|
||||
<main>
|
||||
${body}
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user