Render error pages as HTML
This commit is contained in:
parent
ea58c1f60b
commit
ba7336b4ee
@ -2,6 +2,7 @@ import { Context } from "@oak/oak";
|
|||||||
import { nip19 } from "@nostr/tools";
|
import { nip19 } from "@nostr/tools";
|
||||||
import { log } from "../log.ts";
|
import { log } from "../log.ts";
|
||||||
import { lookupUsernameByPubkey } from "../ldap.ts";
|
import { lookupUsernameByPubkey } from "../ldap.ts";
|
||||||
|
import notFoundHandler from "../handlers/not-found.ts";
|
||||||
|
|
||||||
const naddrHandler = async function (ctx: Context) {
|
const naddrHandler = async function (ctx: Context) {
|
||||||
const naddr = ctx.params.path;
|
const naddr = ctx.params.path;
|
||||||
@ -13,13 +14,11 @@ const naddrHandler = async function (ctx: Context) {
|
|||||||
if (username && r.data.identifier) {
|
if (username && r.data.identifier) {
|
||||||
ctx.response.redirect(`/@${username}/${r.data.identifier}`);
|
ctx.response.redirect(`/@${username}/${r.data.identifier}`);
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e, "yellow");
|
log(e, "yellow");
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
10
handlers/not-found.ts
Normal file
10
handlers/not-found.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Context } from "@oak/oak";
|
||||||
|
import { errorPageHtml } from "../html.ts";
|
||||||
|
|
||||||
|
const notFoundHandler = function (ctx: Context) {
|
||||||
|
const html = errorPageHtml(404, "Not found");
|
||||||
|
ctx.response.body = html;
|
||||||
|
ctx.response.status = 404;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default notFoundHandler;
|
@ -2,6 +2,7 @@ import { Context } from "@oak/oak";
|
|||||||
import { nip19 } from "@nostr/tools";
|
import { nip19 } from "@nostr/tools";
|
||||||
import { log } from "../log.ts";
|
import { log } from "../log.ts";
|
||||||
import { lookupUsernameByPubkey } from "../ldap.ts";
|
import { lookupUsernameByPubkey } from "../ldap.ts";
|
||||||
|
import notFoundHandler from "../handlers/not-found.ts";
|
||||||
|
|
||||||
const nprofileHandler = async function (ctx: Context) {
|
const nprofileHandler = async function (ctx: Context) {
|
||||||
const nprofile = ctx.params.path;
|
const nprofile = ctx.params.path;
|
||||||
@ -13,13 +14,11 @@ const nprofileHandler = async function (ctx: Context) {
|
|||||||
if (username) {
|
if (username) {
|
||||||
ctx.response.redirect(`/@${username}`);
|
ctx.response.redirect(`/@${username}`);
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e, "yellow");
|
log(e, "yellow");
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { Context } from "@oak/oak";
|
|||||||
import { nip19 } from "@nostr/tools";
|
import { nip19 } from "@nostr/tools";
|
||||||
import { log } from "../log.ts";
|
import { log } from "../log.ts";
|
||||||
import { lookupUsernameByPubkey } from "../ldap.ts";
|
import { lookupUsernameByPubkey } from "../ldap.ts";
|
||||||
|
import notFoundHandler from "../handlers/not-found.ts";
|
||||||
|
|
||||||
const npubHandler = async function (ctx: Context) {
|
const npubHandler = async function (ctx: Context) {
|
||||||
const npub = ctx.params.path;
|
const npub = ctx.params.path;
|
||||||
@ -13,13 +14,11 @@ const npubHandler = async function (ctx: Context) {
|
|||||||
if (username) {
|
if (username) {
|
||||||
ctx.response.redirect(`/@${username}`);
|
ctx.response.redirect(`/@${username}`);
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e, "yellow");
|
log(e, "yellow");
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@ import { fetchArticlesByAuthor, fetchProfileEvent } from "../nostr.ts";
|
|||||||
import { profileAtomFeed } from "../feeds.ts";
|
import { profileAtomFeed } from "../feeds.ts";
|
||||||
import Article from "../models/article.ts";
|
import Article from "../models/article.ts";
|
||||||
import Profile from "../models/profile.ts";
|
import Profile from "../models/profile.ts";
|
||||||
|
import notFoundHandler from "../handlers/not-found.ts";
|
||||||
|
|
||||||
const userAtomFeedHandler = async function (ctx: Context) {
|
const userAtomFeedHandler = async function (ctx: Context) {
|
||||||
const username = ctx.params.user.replace(/^(@|~)/, "");
|
const username = ctx.params.user.replace(/^(@|~)/, "");
|
||||||
const pubkey = await lookupPubkeyByUsername(username);
|
const pubkey = await lookupPubkeyByUsername(username);
|
||||||
|
|
||||||
if (!pubkey) {
|
if (!pubkey) {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,8 +33,7 @@ const userAtomFeedHandler = async function (ctx: Context) {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e, "yellow");
|
log(e, "yellow");
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { fetchProfileEvent, fetchReplaceableEvent } from "../nostr.ts";
|
|||||||
import Article from "../models/article.ts";
|
import Article from "../models/article.ts";
|
||||||
import Profile from "../models/profile.ts";
|
import Profile from "../models/profile.ts";
|
||||||
import { articleHtml } from "../html.ts";
|
import { articleHtml } from "../html.ts";
|
||||||
|
import notFoundHandler from "../handlers/not-found.ts";
|
||||||
|
|
||||||
const userEventHandler = async function (ctx: Context) {
|
const userEventHandler = async function (ctx: Context) {
|
||||||
const username = ctx.params.user.replace(/^(@|~)/, "");
|
const username = ctx.params.user.replace(/^(@|~)/, "");
|
||||||
@ -12,8 +13,7 @@ const userEventHandler = async function (ctx: Context) {
|
|||||||
const pubkey = await lookupPubkeyByUsername(username);
|
const pubkey = await lookupPubkeyByUsername(username);
|
||||||
|
|
||||||
if (!pubkey) {
|
if (!pubkey) {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,13 +31,11 @@ const userEventHandler = async function (ctx: Context) {
|
|||||||
|
|
||||||
ctx.response.body = html;
|
ctx.response.body = html;
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e, "yellow");
|
log(e, "yellow");
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@ import { fetchArticlesByAuthor, fetchProfileEvent } from "../nostr.ts";
|
|||||||
import Article from "../models/article.ts";
|
import Article from "../models/article.ts";
|
||||||
import Profile from "../models/profile.ts";
|
import Profile from "../models/profile.ts";
|
||||||
import { profilePageHtml } from "../html.ts";
|
import { profilePageHtml } from "../html.ts";
|
||||||
|
import notFoundHandler from "../handlers/not-found.ts";
|
||||||
|
|
||||||
const userProfileHandler = async function (ctx: Context) {
|
const userProfileHandler = async function (ctx: Context) {
|
||||||
const username = ctx.params.path.replace(/^(@|~)/, "");
|
const username = ctx.params.path.replace(/^(@|~)/, "");
|
||||||
const pubkey = await lookupPubkeyByUsername(username);
|
const pubkey = await lookupPubkeyByUsername(username);
|
||||||
|
|
||||||
if (!pubkey) {
|
if (!pubkey) {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,13 +27,11 @@ const userProfileHandler = async function (ctx: Context) {
|
|||||||
|
|
||||||
ctx.response.body = html;
|
ctx.response.body = html;
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e, "yellow");
|
log(e, "yellow");
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
20
html.ts
20
html.ts
@ -2,7 +2,13 @@ import { localizeDate } from "./dates.ts";
|
|||||||
import Article from "./models/article.ts";
|
import Article from "./models/article.ts";
|
||||||
import Profile from "./models/profile.ts";
|
import Profile from "./models/profile.ts";
|
||||||
|
|
||||||
function htmlLayout(title: string, body: string, profile: Profile): string {
|
function htmlLayout(title: string, body: string, profile?: Profile): string {
|
||||||
|
let feedLinksHtml = "";
|
||||||
|
if (profile) {
|
||||||
|
feedLinksHtml =
|
||||||
|
`<link rel="alternate" type="application/atom+xml" href="/@${profile.username}/articles.atom" title="Articles by ${profile.name}" />`;
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@ -11,7 +17,7 @@ function htmlLayout(title: string, body: string, profile: Profile): string {
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<title>${title}</title>
|
<title>${title}</title>
|
||||||
<link rel="alternate" type="application/atom+xml" href="/@${profile.username}/articles.atom" title="Articles by ${profile.name}" />
|
${feedLinksHtml}
|
||||||
<link rel="stylesheet" type="text/css" href="/assets/css/layout.css" />
|
<link rel="stylesheet" type="text/css" href="/assets/css/layout.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/assets/css/themes/default-light.css" />
|
<link rel="stylesheet" type="text/css" href="/assets/css/themes/default-light.css" />
|
||||||
</head>
|
</head>
|
||||||
@ -22,6 +28,16 @@ function htmlLayout(title: string, body: string, profile: Profile): string {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function errorPageHtml(statusCode: number, title: string): string {
|
||||||
|
const body = `
|
||||||
|
<main>
|
||||||
|
<h1>${statusCode} - ${title}</h1>
|
||||||
|
</main>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return htmlLayout(title, body);
|
||||||
|
}
|
||||||
|
|
||||||
export function articleHtml(article: Article, profile: Profile): string {
|
export function articleHtml(article: Article, profile: Profile): string {
|
||||||
const publishedAtFormatted = localizeDate(article.publishedAt);
|
const publishedAtFormatted = localizeDate(article.publishedAt);
|
||||||
|
|
||||||
|
13
server.ts
13
server.ts
@ -6,6 +6,7 @@ import npubHandler from "./handlers/npub.ts";
|
|||||||
import userProfileHandler from "./handlers/user-profile.ts";
|
import userProfileHandler from "./handlers/user-profile.ts";
|
||||||
import userEventHandler from "./handlers/user-event.ts";
|
import userEventHandler from "./handlers/user-event.ts";
|
||||||
import userAtomFeedHandler from "./handlers/user-atom-feed.ts";
|
import userAtomFeedHandler from "./handlers/user-atom-feed.ts";
|
||||||
|
import notFoundHandler from "./handlers/not-found.ts";
|
||||||
|
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
|
||||||
@ -21,8 +22,7 @@ router.get("/:path", async (ctx: ctx) => {
|
|||||||
} else if (path.startsWith("@") || path.startsWith("~")) {
|
} else if (path.startsWith("@") || path.startsWith("~")) {
|
||||||
await userProfileHandler(ctx);
|
await userProfileHandler(ctx);
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -35,8 +35,7 @@ router.get("/:user/:kind.atom", async (ctx: ctx) => {
|
|||||||
) {
|
) {
|
||||||
await userAtomFeedHandler(ctx);
|
await userAtomFeedHandler(ctx);
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,8 +45,7 @@ router.get("/:user/:identifier", async (ctx: ctx) => {
|
|||||||
if (user.startsWith("@") || user.startsWith("~")) {
|
if (user.startsWith("@") || user.startsWith("~")) {
|
||||||
await userEventHandler(ctx);
|
await userEventHandler(ctx);
|
||||||
} else {
|
} else {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,8 +57,7 @@ router.get("/assets/:path*", async (ctx) => {
|
|||||||
root: `${Deno.cwd()}/assets`,
|
root: `${Deno.cwd()}/assets`,
|
||||||
});
|
});
|
||||||
} catch (_e) {
|
} catch (_e) {
|
||||||
ctx.response.status = 404;
|
notFoundHandler(ctx);
|
||||||
ctx.response.body = "Not Found";
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user