Compare commits
3 Commits
bfc1f0839a
...
eaf363ee27
| Author | SHA1 | Date | |
|---|---|---|---|
|
eaf363ee27
|
|||
|
0ea9db3473
|
|||
|
8d6acca5e9
|
@@ -4,7 +4,7 @@ import datetime
|
|||||||
import requests
|
import requests
|
||||||
from mail import sendEmail
|
from mail import sendEmail
|
||||||
from sol import create_transaction
|
from sol import create_transaction
|
||||||
from tools import getClientIP, getGitCommit
|
from tools import getClientIP, getGitCommit, json_response
|
||||||
|
|
||||||
|
|
||||||
api_bp = Blueprint('api', __name__)
|
api_bp = Blueprint('api', __name__)
|
||||||
@@ -32,13 +32,18 @@ def help_get():
|
|||||||
"/version": "Get the current version of the website",
|
"/version": "Get the current version of the website",
|
||||||
"/help": "Get this help message"
|
"/help": "Get this help message"
|
||||||
},
|
},
|
||||||
"version": getGitCommit()
|
"base_url": "/api/v1",
|
||||||
|
"version": getGitCommit(),
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"status": 200
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/version")
|
@api_bp.route("/version")
|
||||||
def version_get():
|
def version_get():
|
||||||
return jsonify({"version": getGitCommit()})
|
return jsonify({"version": getGitCommit()})
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/time")
|
@api_bp.route("/time")
|
||||||
def time_get():
|
def time_get():
|
||||||
timezone_offset = datetime.timedelta(hours=ncConfig["time-zone"])
|
timezone_offset = datetime.timedelta(hours=ncConfig["time-zone"])
|
||||||
@@ -48,12 +53,20 @@ def time_get():
|
|||||||
"timestring": time.strftime("%A, %B %d, %Y %I:%M %p"),
|
"timestring": time.strftime("%A, %B %d, %Y %I:%M %p"),
|
||||||
"timestamp": time.timestamp(),
|
"timestamp": time.timestamp(),
|
||||||
"timezone": ncConfig["time-zone"],
|
"timezone": ncConfig["time-zone"],
|
||||||
"timeISO": time.isoformat()
|
"timeISO": time.isoformat(),
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"status": 200
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/timezone")
|
@api_bp.route("/timezone")
|
||||||
def timezone_get():
|
def timezone_get():
|
||||||
return jsonify({"timezone": ncConfig["time-zone"]})
|
return jsonify({
|
||||||
|
"timezone": ncConfig["time-zone"],
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"status": 200
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/timezone", methods=["POST"])
|
@api_bp.route("/timezone", methods=["POST"])
|
||||||
def timezone_post():
|
def timezone_post():
|
||||||
@@ -62,88 +75,93 @@ def timezone_post():
|
|||||||
conf = requests.get(
|
conf = requests.get(
|
||||||
"https://cloud.woodburn.au/s/4ToXgFe3TnnFcN7/download/website-conf.json")
|
"https://cloud.woodburn.au/s/4ToXgFe3TnnFcN7/download/website-conf.json")
|
||||||
if conf.status_code != 200:
|
if conf.status_code != 200:
|
||||||
return jsonify({"message": "Error: Could not get timezone"})
|
return json_response(request, "Error: Could not get timezone", 500)
|
||||||
if not conf.json():
|
if not conf.json():
|
||||||
return jsonify({"message": "Error: Could not get timezone"})
|
return json_response(request, "Error: Could not get timezone", 500)
|
||||||
conf = conf.json()
|
conf = conf.json()
|
||||||
if "time-zone" not in conf:
|
if "time-zone" not in conf:
|
||||||
return jsonify({"message": "Error: Could not get timezone"})
|
return json_response(request, "Error: Could not get timezone", 500)
|
||||||
|
|
||||||
ncConfig = conf
|
ncConfig = conf
|
||||||
return jsonify({"message": "Successfully pulled latest timezone", "timezone": ncConfig["time-zone"]})
|
return jsonify({
|
||||||
|
"message": "Successfully pulled latest timezone",
|
||||||
|
"timezone": ncConfig["time-zone"],
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"status": 200
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/message")
|
@api_bp.route("/message")
|
||||||
def message_get():
|
def message_get():
|
||||||
return jsonify({"message": ncConfig["message"]})
|
return jsonify({
|
||||||
|
"message": ncConfig["message"],
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"status": 200
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/ip")
|
@api_bp.route("/ip")
|
||||||
def ip_get():
|
def ip_get():
|
||||||
return jsonify({"ip": getClientIP(request)})
|
return jsonify({
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"status": 200
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/email", methods=["POST"])
|
@api_bp.route("/email", methods=["POST"])
|
||||||
def email_post():
|
def email_post():
|
||||||
# Verify json
|
# Verify json
|
||||||
if not request.is_json:
|
if not request.is_json:
|
||||||
return jsonify({
|
return json_response(request, "415 Unsupported Media Type", 415)
|
||||||
"status": 400,
|
|
||||||
"error": "Bad request JSON Data missing"
|
|
||||||
})
|
|
||||||
|
|
||||||
# Check if api key sent
|
# Check if api key sent
|
||||||
data = request.json
|
data = request.json
|
||||||
if not data:
|
if not data:
|
||||||
return jsonify({
|
return json_response(request, "400 Bad Request", 400)
|
||||||
"status": 400,
|
|
||||||
"error": "Bad request JSON Data missing"
|
|
||||||
})
|
|
||||||
|
|
||||||
if "key" not in data:
|
if "key" not in data:
|
||||||
return jsonify({
|
return json_response(request, "400 Bad Request 'key' missing", 400)
|
||||||
"status": 401,
|
|
||||||
"error": "Unauthorized 'key' missing"
|
|
||||||
})
|
|
||||||
|
|
||||||
if data["key"] != os.getenv("EMAIL_KEY"):
|
if data["key"] != os.getenv("EMAIL_KEY"):
|
||||||
return jsonify({
|
return json_response(request, "401 Unauthorized", 401)
|
||||||
"status": 401,
|
|
||||||
"error": "Unauthorized 'key' invalid"
|
|
||||||
})
|
|
||||||
|
|
||||||
|
# TODO: Add client info to email
|
||||||
return sendEmail(data)
|
return sendEmail(data)
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/project")
|
@api_bp.route("/project")
|
||||||
def project_get():
|
def project_get():
|
||||||
|
gitinfo = {
|
||||||
|
"website": None,
|
||||||
|
}
|
||||||
try:
|
try:
|
||||||
git = requests.get(
|
git = requests.get(
|
||||||
"https://git.woodburn.au/users/nathanwoodburn/activities/feeds?only-performed-by=true&limit=1",
|
"https://git.woodburn.au/api/v1/users/nathanwoodburn/activities/feeds?only-performed-by=true&limit=1",
|
||||||
headers={"Authorization": os.getenv("git_token")},
|
headers={"Authorization": os.getenv("git_token")},
|
||||||
)
|
)
|
||||||
git = git.json()
|
git = git.json()
|
||||||
git = git[0]
|
git = git[0]
|
||||||
repo_name = git["repo"]["name"]
|
repo_name = git["repo"]["name"]
|
||||||
repo_name = repo_name.lower()
|
repo_name = repo_name.lower()
|
||||||
repo_description = git["repo"]["description"]
|
repo_description = git["repo"]["description"]
|
||||||
|
gitinfo["name"] = repo_name
|
||||||
|
gitinfo["description"] = repo_description
|
||||||
|
gitinfo["url"] = git["repo"]["html_url"]
|
||||||
|
if "website" in git["repo"]:
|
||||||
|
gitinfo["website"] = git["repo"]["website"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
repo_name = "nathanwoodburn.github.io"
|
|
||||||
repo_description = "Personal website"
|
|
||||||
git = {
|
|
||||||
"repo": {
|
|
||||||
"html_url": "https://nathan.woodburn.au",
|
|
||||||
"name": "nathanwoodburn.github.io",
|
|
||||||
"description": "Personal website",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print(f"Error getting git data: {e}")
|
print(f"Error getting git data: {e}")
|
||||||
|
return json_response(request, "500 Internal Server Error", 500)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"repo_name": repo_name,
|
"repo_name": repo_name,
|
||||||
"repo_description": repo_description,
|
"repo_description": repo_description,
|
||||||
"git": git,
|
"repo": gitinfo,
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"status": 200
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
# region Solana Links
|
# region Solana Links
|
||||||
SOLANA_HEADERS = {
|
SOLANA_HEADERS = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -152,7 +170,6 @@ SOLANA_HEADERS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route("/donate", methods=["GET", "OPTIONS"])
|
@api_bp.route("/donate", methods=["GET", "OPTIONS"])
|
||||||
def sol_donate_get():
|
def sol_donate_get():
|
||||||
data = {
|
data = {
|
||||||
@@ -204,8 +221,7 @@ def sol_donate_post(amount):
|
|||||||
|
|
||||||
if not request.json:
|
if not request.json:
|
||||||
return jsonify({"message": "Error: No JSON data provided"}), 400, SOLANA_HEADERS
|
return jsonify({"message": "Error: No JSON data provided"}), 400, SOLANA_HEADERS
|
||||||
|
|
||||||
|
|
||||||
if "account" not in request.json:
|
if "account" not in request.json:
|
||||||
return jsonify({"message": "Error: No account provided"}), 400, SOLANA_HEADERS
|
return jsonify({"message": "Error: No account provided"}), 400, SOLANA_HEADERS
|
||||||
|
|
||||||
@@ -215,7 +231,7 @@ def sol_donate_post(amount):
|
|||||||
try:
|
try:
|
||||||
amount = float(amount)
|
amount = float(amount)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
amount = 1 # Default to 1 SOL if invalid
|
amount = 1 # Default to 1 SOL if invalid
|
||||||
|
|
||||||
if amount < 0.0001:
|
if amount < 0.0001:
|
||||||
return jsonify({"message": "Error: Amount too small"}), 400, SOLANA_HEADERS
|
return jsonify({"message": "Error: Amount too small"}), 400, SOLANA_HEADERS
|
||||||
@@ -224,4 +240,3 @@ def sol_donate_post(amount):
|
|||||||
return jsonify({"message": "Success", "transaction": transaction}), 200, SOLANA_HEADERS
|
return jsonify({"message": "Success", "transaction": transaction}), 200, SOLANA_HEADERS
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
from flask import Blueprint, render_template, request
|
from flask import Blueprint, render_template, request, jsonify
|
||||||
import markdown
|
import markdown
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
import re
|
import re
|
||||||
|
from tools import isCurl, getClientIP
|
||||||
|
|
||||||
blog_bp = Blueprint('blog', __name__)
|
blog_bp = Blueprint('blog', __name__)
|
||||||
|
|
||||||
@@ -105,30 +106,76 @@ def render_blog_home(handshake_scripts=None):
|
|||||||
|
|
||||||
@blog_bp.route("/")
|
@blog_bp.route("/")
|
||||||
def blog_index_get():
|
def blog_index_get():
|
||||||
global handshake_scripts
|
if not isCurl(request):
|
||||||
|
global handshake_scripts
|
||||||
|
|
||||||
# If localhost, don't load handshake
|
# If localhost, don't load handshake
|
||||||
if (
|
if (
|
||||||
request.host == "localhost:5000"
|
request.host == "localhost:5000"
|
||||||
or request.host == "127.0.0.1:5000"
|
or request.host == "127.0.0.1:5000"
|
||||||
or os.getenv("dev") == "true"
|
or os.getenv("dev") == "true"
|
||||||
or request.host == "test.nathan.woodburn.au"
|
or request.host == "test.nathan.woodburn.au"
|
||||||
):
|
):
|
||||||
handshake_scripts = ""
|
handshake_scripts = ""
|
||||||
|
return render_blog_home(handshake_scripts)
|
||||||
|
|
||||||
|
# Get a list of pages
|
||||||
|
blog_pages = list_blog_page_files()
|
||||||
|
# Create a html list of pages
|
||||||
|
blog_pages = [
|
||||||
|
{"name":page.replace("_", " "),"url":f"/blog/{page}", "download": f"/blog/{page}.md"} for page in blog_pages
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Render the template
|
||||||
|
return jsonify({
|
||||||
|
"status": 200,
|
||||||
|
"message": "Check out my various blog postsa",
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"blogs": blog_pages
|
||||||
|
}), 200
|
||||||
|
|
||||||
return render_blog_home(handshake_scripts)
|
|
||||||
|
|
||||||
|
|
||||||
@blog_bp.route("/<path:path>")
|
@blog_bp.route("/<path:path>")
|
||||||
def blog_path_get(path):
|
def blog_path_get(path):
|
||||||
global handshake_scripts
|
if not isCurl(request):
|
||||||
# If localhost, don't load handshake
|
global handshake_scripts
|
||||||
if (
|
# If localhost, don't load handshake
|
||||||
request.host == "localhost:5000"
|
if (
|
||||||
or request.host == "127.0.0.1:5000"
|
request.host == "localhost:5000"
|
||||||
or os.getenv("dev") == "true"
|
or request.host == "127.0.0.1:5000"
|
||||||
or request.host == "test.nathan.woodburn.au"
|
or os.getenv("dev") == "true"
|
||||||
):
|
or request.host == "test.nathan.woodburn.au"
|
||||||
handshake_scripts = ""
|
):
|
||||||
|
handshake_scripts = ""
|
||||||
|
|
||||||
return render_blog_page(path, handshake_scripts)
|
return render_blog_page(path, handshake_scripts)
|
||||||
|
|
||||||
|
# Convert md to html
|
||||||
|
if not os.path.exists(f"data/blog/{path}.md"):
|
||||||
|
return render_template("404.html"), 404
|
||||||
|
|
||||||
|
with open(f"data/blog/{path}.md", "r") as f:
|
||||||
|
content = f.read()
|
||||||
|
# Get the title from the file name
|
||||||
|
title = path.replace("_", " ")
|
||||||
|
return jsonify({
|
||||||
|
"status": 200,
|
||||||
|
"message": f"Blog post: {title}",
|
||||||
|
"ip": getClientIP(request),
|
||||||
|
"title": title,
|
||||||
|
"content": content,
|
||||||
|
"download": f"/blog/{path}.md"
|
||||||
|
}), 200
|
||||||
|
|
||||||
|
@blog_bp.route("/<path:path>.md")
|
||||||
|
def blog_path_md_get(path):
|
||||||
|
if not os.path.exists(f"data/blog/{path}.md"):
|
||||||
|
return render_template("404.html"), 404
|
||||||
|
|
||||||
|
with open(f"data/blog/{path}.md", "r") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Return the raw markdown file
|
||||||
|
return content, 200, {'Content-Type': 'text/plain; charset=utf-8'}
|
||||||
32
server.py
32
server.py
@@ -149,6 +149,18 @@ def javascript_get(name):
|
|||||||
return error_response(request)
|
return error_response(request)
|
||||||
return send_from_directory("templates/assets/js", request.path.split("/")[-1])
|
return send_from_directory("templates/assets/js", request.path.split("/")[-1])
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/download/<path:path>")
|
||||||
|
def download_get(path):
|
||||||
|
if path not in DOWNLOAD_ROUTES:
|
||||||
|
return error_response(request, message="Invalid download")
|
||||||
|
# Check if file exists
|
||||||
|
path = DOWNLOAD_ROUTES[path]
|
||||||
|
if os.path.isfile(path):
|
||||||
|
return send_file(path)
|
||||||
|
|
||||||
|
return error_response(request, message="File not found")
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
# region PWA routes
|
# region PWA routes
|
||||||
|
|
||||||
@@ -195,6 +207,8 @@ def links_get():
|
|||||||
|
|
||||||
@app.route("/api/<path:function>")
|
@app.route("/api/<path:function>")
|
||||||
def api_legacy_get(function):
|
def api_legacy_get(function):
|
||||||
|
# Check if function is in api blueprint
|
||||||
|
|
||||||
return redirect(f"/api/v1/{function}", code=301)
|
return redirect(f"/api/v1/{function}", code=301)
|
||||||
|
|
||||||
|
|
||||||
@@ -553,7 +567,7 @@ def qrcode_get(data):
|
|||||||
qr.make()
|
qr.make()
|
||||||
|
|
||||||
qr_image: Image.Image = qr.make_image(
|
qr_image: Image.Image = qr.make_image(
|
||||||
fill_color="black", back_color="white").convert('RGB') # type: ignore
|
fill_color="black", back_color="white").convert('RGB') # type: ignore
|
||||||
|
|
||||||
# Add logo
|
# Add logo
|
||||||
logo = Image.open("templates/assets/img/favicon/logo.png")
|
logo = Image.open("templates/assets/img/favicon/logo.png")
|
||||||
@@ -583,18 +597,6 @@ def supersecretpath_get():
|
|||||||
return render_template("ascii.html", ascii_art=ascii_art_html)
|
return render_template("ascii.html", ascii_art=ascii_art_html)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/download/<path:path>")
|
|
||||||
def download_get(path):
|
|
||||||
if path not in DOWNLOAD_ROUTES:
|
|
||||||
return error_response(request, message="Invalid download")
|
|
||||||
# Check if file exists
|
|
||||||
path = DOWNLOAD_ROUTES[path]
|
|
||||||
if os.path.isfile(path):
|
|
||||||
return send_file(path)
|
|
||||||
|
|
||||||
return error_response(request, message="File not found")
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/hosting/send-enquiry", methods=["POST"])
|
@app.route("/hosting/send-enquiry", methods=["POST"])
|
||||||
def hosting_post():
|
def hosting_post():
|
||||||
global EMAIL_REQUEST_COUNT
|
global EMAIL_REQUEST_COUNT
|
||||||
@@ -681,7 +683,7 @@ def hosting_post():
|
|||||||
webhook_url = os.getenv("HOSTING_WEBHOOK")
|
webhook_url = os.getenv("HOSTING_WEBHOOK")
|
||||||
if not webhook_url:
|
if not webhook_url:
|
||||||
return json_response(request, "Hosting webhook not set", 500)
|
return json_response(request, "Hosting webhook not set", 500)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"content": "",
|
"content": "",
|
||||||
"embeds": [
|
"embeds": [
|
||||||
@@ -756,11 +758,13 @@ def catch_all_get(path: str):
|
|||||||
|
|
||||||
return error_response(request)
|
return error_response(request)
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
def not_found(e):
|
def not_found(e):
|
||||||
return error_response(request)
|
return error_response(request)
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(debug=True, port=5000, host="127.0.0.1")
|
app.run(debug=True, port=5000, host="127.0.0.1")
|
||||||
|
|||||||
20
tools.py
20
tools.py
@@ -1,7 +1,8 @@
|
|||||||
from flask import Request, render_template, jsonify
|
from flask import Request, render_template, jsonify, make_response
|
||||||
import os
|
import os
|
||||||
from functools import cache
|
from functools import cache
|
||||||
|
|
||||||
|
|
||||||
def getClientIP(request):
|
def getClientIP(request):
|
||||||
x_forwarded_for = request.headers.get("X-Forwarded-For")
|
x_forwarded_for = request.headers.get("X-Forwarded-For")
|
||||||
if x_forwarded_for:
|
if x_forwarded_for:
|
||||||
@@ -10,6 +11,7 @@ def getClientIP(request):
|
|||||||
ip = request.remote_addr
|
ip = request.remote_addr
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
|
|
||||||
def getGitCommit():
|
def getGitCommit():
|
||||||
# if .git exists, get the latest commit hash
|
# if .git exists, get the latest commit hash
|
||||||
if os.path.isdir(".git"):
|
if os.path.isdir(".git"):
|
||||||
@@ -34,7 +36,7 @@ def getGitCommit():
|
|||||||
def isCurl(request: Request) -> bool:
|
def isCurl(request: Request) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if the request is from curl
|
Check if the request is from curl
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
request (Request): The Flask request object
|
request (Request): The Flask request object
|
||||||
Returns:
|
Returns:
|
||||||
@@ -47,6 +49,7 @@ def isCurl(request: Request) -> bool:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def isCrawler(request: Request) -> bool:
|
def isCrawler(request: Request) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if the request is from a web crawler (e.g., Googlebot, Bingbot)
|
Check if the request is from a web crawler (e.g., Googlebot, Bingbot)
|
||||||
@@ -79,6 +82,7 @@ def getFilePath(name, path):
|
|||||||
if name in files:
|
if name in files:
|
||||||
return os.path.join(root, name)
|
return os.path.join(root, name)
|
||||||
|
|
||||||
|
|
||||||
def json_response(request: Request, message: str = "404 Not Found", code: int = 404):
|
def json_response(request: Request, message: str = "404 Not Found", code: int = 404):
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
@@ -92,8 +96,14 @@ def json_response(request: Request, message: str = "404 Not Found", code: int =
|
|||||||
def error_response(request: Request, message: str = "404 Not Found", code: int = 404, force_json: bool = False):
|
def error_response(request: Request, message: str = "404 Not Found", code: int = 404, force_json: bool = False):
|
||||||
if force_json or isCurl(request):
|
if force_json or isCurl(request):
|
||||||
return json_response(request, message, code)
|
return json_response(request, message, code)
|
||||||
|
|
||||||
# Check if <error code>.html exists in templates
|
# Check if <error code>.html exists in templates
|
||||||
|
response = make_response(render_template(
|
||||||
|
"404.html", code=code, message=message), code)
|
||||||
if os.path.isfile(f"templates/{code}.html"):
|
if os.path.isfile(f"templates/{code}.html"):
|
||||||
return render_template(f"{code}.html"), code
|
response = make_response(render_template(
|
||||||
return render_template("404.html"), code
|
f"{code}.html", code=code, message=message), code)
|
||||||
|
|
||||||
|
# Add message to response headers
|
||||||
|
response.headers["X-Error-Message"] = message
|
||||||
|
return response
|
||||||
|
|||||||
Reference in New Issue
Block a user