mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
fix(FastAPI): add custom error templates for certain exceptions
Signed-off-by: Steven Guikal <void@fluix.one>
This commit is contained in:
parent
51b60f4210
commit
e126d431d7
4 changed files with 70 additions and 4 deletions
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import http
|
import http
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
@ -9,18 +10,22 @@ from urllib.parse import quote_plus
|
||||||
from fastapi import FastAPI, HTTPException, Request, Response
|
from fastapi import FastAPI, HTTPException, Request, Response
|
||||||
from fastapi.responses import RedirectResponse
|
from fastapi.responses import RedirectResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
from jinja2 import TemplateNotFound
|
||||||
from prometheus_client import multiprocess
|
from prometheus_client import multiprocess
|
||||||
from sqlalchemy import and_, or_
|
from sqlalchemy import and_, or_
|
||||||
|
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||||
from starlette.middleware.authentication import AuthenticationMiddleware
|
from starlette.middleware.authentication import AuthenticationMiddleware
|
||||||
from starlette.middleware.sessions import SessionMiddleware
|
from starlette.middleware.sessions import SessionMiddleware
|
||||||
|
|
||||||
import aurweb.config
|
import aurweb.config
|
||||||
import aurweb.logging
|
import aurweb.logging
|
||||||
|
import aurweb.pkgbase.util as pkgbaseutil
|
||||||
|
|
||||||
from aurweb import prometheus, util
|
from aurweb import prometheus, util
|
||||||
from aurweb.auth import BasicAuthBackend
|
from aurweb.auth import BasicAuthBackend
|
||||||
from aurweb.db import get_engine, query
|
from aurweb.db import get_engine, query
|
||||||
from aurweb.models import AcceptedTerm, Term
|
from aurweb.models import AcceptedTerm, Term
|
||||||
|
from aurweb.packages.util import get_pkg_or_base
|
||||||
from aurweb.prometheus import instrumentator
|
from aurweb.prometheus import instrumentator
|
||||||
from aurweb.routers import APP_ROUTES
|
from aurweb.routers import APP_ROUTES
|
||||||
from aurweb.templates import make_context, render_template
|
from aurweb.templates import make_context, render_template
|
||||||
|
@ -89,7 +94,7 @@ def child_exit(server, worker): # pragma: no cover
|
||||||
multiprocess.mark_process_dead(worker.pid)
|
multiprocess.mark_process_dead(worker.pid)
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(HTTPException)
|
@app.exception_handler(StarletteHTTPException)
|
||||||
async def http_exception_handler(request: Request, exc: HTTPException) \
|
async def http_exception_handler(request: Request, exc: HTTPException) \
|
||||||
-> Response:
|
-> Response:
|
||||||
""" Handle an HTTPException thrown in a route. """
|
""" Handle an HTTPException thrown in a route. """
|
||||||
|
@ -97,8 +102,24 @@ async def http_exception_handler(request: Request, exc: HTTPException) \
|
||||||
context = make_context(request, phrase)
|
context = make_context(request, phrase)
|
||||||
context["exc"] = exc
|
context["exc"] = exc
|
||||||
context["phrase"] = phrase
|
context["phrase"] = phrase
|
||||||
return render_template(request, "errors/detail.html", context,
|
|
||||||
exc.status_code)
|
# Additional context for some exceptions.
|
||||||
|
if exc.status_code == http.HTTPStatus.NOT_FOUND:
|
||||||
|
tokens = request.url.path.split("/")
|
||||||
|
matches = re.match("^([a-z0-9][a-z0-9.+_-]*?)(\\.git)?$", tokens[1])
|
||||||
|
if matches:
|
||||||
|
try:
|
||||||
|
pkgbase = get_pkg_or_base(matches.group(1))
|
||||||
|
context = pkgbaseutil.make_context(request, pkgbase)
|
||||||
|
except HTTPException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
return render_template(request, f"errors/{exc.status_code}.html",
|
||||||
|
context, exc.status_code)
|
||||||
|
except TemplateNotFound:
|
||||||
|
return render_template(request, "errors/detail.html",
|
||||||
|
context, exc.status_code)
|
||||||
|
|
||||||
|
|
||||||
@app.middleware("http")
|
@app.middleware("http")
|
||||||
|
|
|
@ -87,11 +87,14 @@ def provides_markup(provides: Providers) -> str:
|
||||||
|
|
||||||
def get_pkg_or_base(
|
def get_pkg_or_base(
|
||||||
name: str,
|
name: str,
|
||||||
cls: Union[models.Package, models.PackageBase] = models.PackageBase):
|
cls: Union[models.Package, models.PackageBase] = models.PackageBase) \
|
||||||
|
-> Union[models.Package, models.PackageBase]:
|
||||||
""" Get a PackageBase instance by its name or raise a 404 if
|
""" Get a PackageBase instance by its name or raise a 404 if
|
||||||
it can't be found in the database.
|
it can't be found in the database.
|
||||||
|
|
||||||
:param name: {Package,PackageBase}.Name
|
:param name: {Package,PackageBase}.Name
|
||||||
|
:param exception: Whether to raise an HTTPException or simply return None if
|
||||||
|
the package can't be found.
|
||||||
:raises HTTPException: With status code 404 if record doesn't exist
|
:raises HTTPException: With status code 404 if record doesn't exist
|
||||||
:return: {Package,PackageBase} instance
|
:return: {Package,PackageBase} instance
|
||||||
"""
|
"""
|
||||||
|
|
34
templates/errors/404.html
Normal file
34
templates/errors/404.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{% extends 'partials/layout.html' %}
|
||||||
|
|
||||||
|
{% block pageContent %}
|
||||||
|
<div id="error-page" class="box">
|
||||||
|
<h2>404 - {% trans %}Page Not Found{% endtrans %}</h2>
|
||||||
|
<p>{% trans %}Sorry, the page you've requested does not exist.{% endtrans %}</p>
|
||||||
|
{% if pkgbase %}
|
||||||
|
<ul>
|
||||||
|
{% set pkgname_strong="<strong>%s</strong>" | format(pkgbase.Name) %}
|
||||||
|
<li>
|
||||||
|
<strong>{% trans %}Note{% endtrans %}:</strong>
|
||||||
|
{% trans %}Git clone URLs are not meant to be opened in a browser.{% endtrans %}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% set gitcmd="<code>git clone %s</code>" | format(git_clone_uri_anon | format(pkgbase.Name)) %}
|
||||||
|
{% if is_maintainer %}
|
||||||
|
{% set gitcmd="<code>git clone %s</code>" | format(git_clone_uri_priv | format(pkgbase.Name)) %}
|
||||||
|
{% endif %}
|
||||||
|
{{
|
||||||
|
"To clone the Git repository of %s, run %s."
|
||||||
|
| tr | format(pkgname_strong, gitcmd) | safe
|
||||||
|
}}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% set pkglink='<a href="/pkgbase/%s">' | format(pkgbase.Name) %}
|
||||||
|
{{
|
||||||
|
"Click %shere%s to return to the %s details page."
|
||||||
|
| tr | format(pkglink, "</a>", pkgname_strong) | safe
|
||||||
|
}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
8
templates/errors/503.html
Normal file
8
templates/errors/503.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'partials/layout.html' %}
|
||||||
|
|
||||||
|
{% block pageContent %}
|
||||||
|
<div id="error-page" class="box">
|
||||||
|
<h2>503 - {% trans %}Service Unavailable{% endtrans %}</h2>
|
||||||
|
<p>{% trans %}Don't panic! This site is down due to maintenance. We will be back soon.{% endtrans %}</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Add table
Reference in a new issue