Skip to content

Commit 8567a16

Browse files
authored
Merge pull request #12 from opencitations/2025-add-404-page
add 404 page
2 parents 7f88aa5 + 230835f commit 8567a16

File tree

3 files changed

+219
-3
lines changed

3 files changed

+219
-3
lines changed

api_oc.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@
6363
"/sparql/meta", "SparqlMeta",
6464
"/index/?", "RedirectIndex",
6565
"/meta/?", "RedirectMeta",
66-
"/(index)(/v[0-9].*)", "Api",
67-
"/(meta)(/v[0-9].*)", "Api"
66+
"/(index)(/v[1-2].*)", "Api",
67+
"/(meta)(/v1.*)", "Api"
6868

6969
)
7070

@@ -98,9 +98,23 @@
9898
'render': lambda *args, **kwargs: render(*args, **kwargs)
9999
})
100100

101+
# common folder
102+
render_common = web.template.render(c["html"] + '/common', globals={
103+
'str': str,
104+
'isinstance': isinstance
105+
})
106+
107+
def notfound_custom():
108+
"""Custom 404 page"""
109+
return web.notfound(render_common.notfound(web.ctx.home + web.ctx.fullpath))
110+
101111
# App Web.py
102112
app = web.application(urls, globals())
103113

114+
# Custom 404 handler
115+
app.notfound = notfound_custom
116+
117+
# Gunicorn WSGI application
104118
application = app.wsgifunc()
105119

106120
if env_config["redis"]["enabled"]:

docker_version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.6.0sync
1+
1.6.1sync

html-template/common/notfound.html

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
$def with (url)
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>404 - Resource Not Found | OpenCitations</title>
8+
<style>
9+
* {
10+
margin: 0;
11+
padding: 0;
12+
box-sizing: border-box;
13+
}
14+
15+
body {
16+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
17+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18+
min-height: 100vh;
19+
display: flex;
20+
align-items: center;
21+
justify-content: center;
22+
padding: 20px;
23+
}
24+
25+
.container {
26+
background: white;
27+
border-radius: 20px;
28+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
29+
max-width: 600px;
30+
width: 100%;
31+
padding: 60px 40px;
32+
text-align: center;
33+
animation: fadeIn 0.5s ease-in;
34+
}
35+
36+
@keyframes fadeIn {
37+
from {
38+
opacity: 0;
39+
transform: translateY(-20px);
40+
}
41+
to {
42+
opacity: 1;
43+
transform: translateY(0);
44+
}
45+
}
46+
47+
.error-code {
48+
font-size: 120px;
49+
font-weight: bold;
50+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
51+
-webkit-background-clip: text;
52+
-webkit-text-fill-color: transparent;
53+
background-clip: text;
54+
line-height: 1;
55+
margin-bottom: 20px;
56+
}
57+
58+
h1 {
59+
font-size: 32px;
60+
color: #2d3748;
61+
margin-bottom: 15px;
62+
}
63+
64+
.description {
65+
font-size: 18px;
66+
color: #718096;
67+
margin-bottom: 30px;
68+
line-height: 1.6;
69+
}
70+
71+
.resource-info {
72+
background: #f7fafc;
73+
border-left: 4px solid #667eea;
74+
padding: 15px;
75+
margin: 25px 0;
76+
border-radius: 5px;
77+
text-align: left;
78+
}
79+
80+
.resource-info strong {
81+
color: #2d3748;
82+
display: block;
83+
margin-bottom: 5px;
84+
}
85+
86+
.resource-info code {
87+
background: #edf2f7;
88+
padding: 2px 6px;
89+
border-radius: 3px;
90+
font-size: 14px;
91+
color: #667eea;
92+
word-break: break-all;
93+
}
94+
95+
.suggestions {
96+
margin-top: 40px;
97+
text-align: left;
98+
padding: 20px;
99+
background: #f7fafc;
100+
border-radius: 10px;
101+
}
102+
103+
.suggestions h3 {
104+
color: #2d3748;
105+
margin-bottom: 15px;
106+
font-size: 18px;
107+
}
108+
109+
.suggestions ul {
110+
list-style: none;
111+
padding-left: 0;
112+
}
113+
114+
.suggestions li {
115+
color: #4a5568;
116+
padding: 8px 0;
117+
padding-left: 25px;
118+
position: relative;
119+
}
120+
121+
.suggestions li:before {
122+
content: "→";
123+
position: absolute;
124+
left: 0;
125+
color: #667eea;
126+
font-weight: bold;
127+
}
128+
129+
.suggestions a {
130+
color: #667eea;
131+
text-decoration: none;
132+
}
133+
134+
.suggestions a:hover {
135+
text-decoration: underline;
136+
}
137+
138+
.footer {
139+
margin-top: 40px;
140+
padding-top: 20px;
141+
border-top: 1px solid #e2e8f0;
142+
color: #a0aec0;
143+
font-size: 14px;
144+
}
145+
146+
.footer a {
147+
color: #667eea;
148+
text-decoration: none;
149+
font-weight: 600;
150+
}
151+
152+
.footer a:hover {
153+
text-decoration: underline;
154+
}
155+
156+
@media (max-width: 600px) {
157+
.container {
158+
padding: 40px 25px;
159+
}
160+
161+
.error-code {
162+
font-size: 80px;
163+
}
164+
165+
h1 {
166+
font-size: 24px;
167+
}
168+
169+
.description {
170+
font-size: 16px;
171+
}
172+
}
173+
</style>
174+
</head>
175+
<body>
176+
<div class="container">
177+
<div class="error-code">404</div>
178+
<h1>Resource Not Found</h1>
179+
<p class="description">
180+
Sorry, we couldn't find the resource you're looking for.
181+
</p>
182+
183+
<div class="resource-info">
184+
<strong>Requested Resource:</strong>
185+
<code>$url</code>
186+
</div>
187+
188+
<div class="suggestions">
189+
<h3>What you can do:</h3>
190+
<ul>
191+
<li>Check if the URL is correct</li>
192+
<li>Read our <a href="https://api.opencitations.net">API documentation</a></li>
193+
<li>Visit our <a href="https://opencitations.net">Website</a></li>
194+
</ul>
195+
</div>
196+
197+
<div class="footer">
198+
<p><a href="https://opencitations.net">OpenCitations</a></p>
199+
</div>
200+
</div>
201+
</body>
202+
</html>

0 commit comments

Comments
 (0)