Skip to content
This repository was archived by the owner on Jan 17, 2023. It is now read-only.

Commit 3ba6f26

Browse files
committed
Fix #1548, add styled 404 page.
Does not change 404s for routes which are APIs, i.e., not seen by humans.
1 parent 0565da7 commit 3ba6f26

File tree

5 files changed

+77
-7
lines changed

5 files changed

+77
-7
lines changed

server/src/pages/not-found/model.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
exports.createModel = function (req) {
2+
return {
3+
title: "Page Not Found"
4+
};
5+
};

server/src/pages/not-found/page.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const { Page } = require("../../reactruntime");
2+
const viewModule = require("./view");
3+
4+
exports.page = new Page({
5+
dir: __dirname,
6+
viewModule,
7+
noBrowserJavascript: true
8+
});

server/src/pages/not-found/server.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const reactrender = require("../../reactrender");
2+
3+
exports.notFound = function (req, res) {
4+
const page = require("./page").page;
5+
res.status(404);
6+
reactrender.render(req, res, page);
7+
};

server/src/pages/not-found/view.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* globals location*/
2+
const reactruntime = require("../../reactruntime");
3+
const { Footer } = require("../../footer-view.js");
4+
const React = require("react");
5+
6+
class Head extends React.Component {
7+
render() {
8+
return (
9+
<reactruntime.HeadTemplate {...this.props}>
10+
<link rel="stylesheet" href={this.props.staticLink("css/simple.css")} />
11+
</reactruntime.HeadTemplate>
12+
);
13+
}
14+
}
15+
16+
class Body extends React.Component {
17+
constructor(props) {
18+
super(props);
19+
this.state = {defaultSearch: props.defaultSearch};
20+
}
21+
22+
render() {
23+
return (
24+
<reactruntime.BodyTemplate {...this.props}>
25+
<div className="column-space full-height default-color-scheme">
26+
<div className="header">
27+
<h1><a href="/shots">Page Shot</a></h1>
28+
</div>
29+
<div className="responsive-wrapper flex-1">
30+
<h2>{this.props.title}</h2>
31+
<p>
32+
The page was not found.
33+
</p>
34+
</div>
35+
<Footer forUrl="legal" {...this.props} />
36+
</div>
37+
</reactruntime.BodyTemplate>
38+
)
39+
}
40+
}
41+
42+
exports.HeadFactory = React.createFactory(Head);
43+
exports.BodyFactory = React.createFactory(Body);

server/src/server.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const escapeHtml = require("escape-html");
7979
const validUrl = require("valid-url");
8080
const { createProxyUrl } = require("./proxy-url");
8181
const statsd = require("./statsd");
82+
const { notFound } = require("./pages/not-found/server");
8283

8384
const PROXY_HEADER_WHITELIST = {
8485
"content-type": true,
@@ -708,7 +709,7 @@ app.get("/images/:imageid", function (req, res) {
708709
req.params.imageid
709710
).then((obj) => {
710711
if (obj === null) {
711-
simpleResponse(res, "Not Found", 404);
712+
notFound(req, res);
712713
} else {
713714
let hasher = require("crypto").createHash("sha1");
714715
hasher.update(req.params.imageid);
@@ -810,14 +811,14 @@ require("./exporter").setup(app);
810811
app.get("/:id/:domain", function (req, res) {
811812
let shotId = `${req.params.id}/${req.params.domain}`;
812813
Shot.get(req.backend, shotId).then((shot) => {
813-
let notFound = false;
814+
let noSuchShot = false;
814815
if (! shot) {
815-
notFound = true;
816+
noSuchShot = true;
816817
} else if (shot.clipNames().length === 0 && ! shot.deleted) {
817818
// Deleted shots always appear to have no clips
818819
}
819-
if (notFound) {
820-
simpleResponse(res, "Not found", 404);
820+
if (noSuchShot) {
821+
notFound(req, res);
821822
return;
822823
}
823824
req.shot = shot;
@@ -862,7 +863,8 @@ app.get("/oembed", function (req, res) {
862863
let shotId = match[1] + "/" + match[2];
863864
Shot.get(req.backend, shotId).then((shot) => {
864865
if (! shot) {
865-
return simpleResponse(res, "No such shot", 404);
866+
notFound(req, res);
867+
return;
866868
}
867869
let body = shot.oembedJson({maxheight, maxwidth});
868870
res.header("Content-Type", "application/json");
@@ -993,7 +995,7 @@ contentApp.get("/content/:id/:domain", function (req, res) {
993995
let shotId = `${req.params.id}/${req.params.domain}`;
994996
Shot.getFullShot(req.backend, shotId).then((shot) => {
995997
if (! shot) {
996-
simpleResponse(res, "Not found", 404);
998+
notFound(req, res);
997999
return;
9981000
}
9991001
res.send(shot.staticHtml({
@@ -1142,3 +1144,8 @@ linker.init().then(() => {
11421144
});
11431145

11441146
require("./jobs").start();
1147+
1148+
/* General 404 handler: */
1149+
app.use(function(req, res, next) {
1150+
notFound(req, res);
1151+
});

0 commit comments

Comments
 (0)