uhhh lots of things
All checks were successful
All checks were successful
This commit is contained in:
parent
0a6d5b8a90
commit
c6f36d0408
12
config.toml
12
config.toml
@ -3,7 +3,11 @@ content_dir = "/home/dubey/projects/foldsite/example/content"
|
|||||||
templates_dir = "/home/dubey/projects/foldsite/example/templates"
|
templates_dir = "/home/dubey/projects/foldsite/example/templates"
|
||||||
styles_dir = "/home/dubey/projects/foldsite/example/styles"
|
styles_dir = "/home/dubey/projects/foldsite/example/styles"
|
||||||
|
|
||||||
[secrets]
|
[server]
|
||||||
password = "YiaysZ4g8QX1R8R"
|
listen_address = "0.0.0.0"
|
||||||
aws_secret_key = "ybCvAq1GQpYg0kEeXc2LqfJl9y6/EXAMPLEKEY"
|
listen_port = 8080
|
||||||
aws_key_id = "AKIASQ5ZB43T69DWV8BQ"
|
enable_admin_browser = false
|
||||||
|
admin_password = "password"
|
||||||
|
max_threads = 4
|
||||||
|
debug = false
|
||||||
|
access_log = true
|
||||||
|
11
main.py
11
main.py
@ -21,7 +21,13 @@ def main():
|
|||||||
r = RouteManager(c)
|
r = RouteManager(c)
|
||||||
t = TemplateHelpers(c)
|
t = TemplateHelpers(c)
|
||||||
|
|
||||||
server = Server()
|
server = Server(
|
||||||
|
debug=c.debug,
|
||||||
|
host=c.listen_address,
|
||||||
|
port=c.listen_port,
|
||||||
|
access_log=c.access_log,
|
||||||
|
workers=c.max_threads,
|
||||||
|
)
|
||||||
|
|
||||||
server.register_template_function("get_sibling_content_files", t.get_sibling_content_files)
|
server.register_template_function("get_sibling_content_files", t.get_sibling_content_files)
|
||||||
server.register_template_function("get_text_document_preview", t.get_text_document_preview)
|
server.register_template_function("get_text_document_preview", t.get_text_document_preview)
|
||||||
@ -33,7 +39,8 @@ def main():
|
|||||||
server.register_route("/", r.default_route, defaults={"path": ""})
|
server.register_route("/", r.default_route, defaults={"path": ""})
|
||||||
server.register_route("/<path:path>", r.default_route)
|
server.register_route("/<path:path>", r.default_route)
|
||||||
|
|
||||||
file_manager_bp = create_filemanager_blueprint(c.content_dir, url_prefix='/admin', auth_password="password")
|
if c.admin_browser:
|
||||||
|
file_manager_bp = create_filemanager_blueprint(c.content_dir, url_prefix='/admin', auth_password=c.admin_password)
|
||||||
server.app.register_blueprint(file_manager_bp)
|
server.app.register_blueprint(file_manager_bp)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -9,10 +9,19 @@ class Configuration:
|
|||||||
|
|
||||||
def __init__(self, config_path):
|
def __init__(self, config_path):
|
||||||
self.config_path = config_path
|
self.config_path = config_path
|
||||||
|
|
||||||
self.content_dir: Path = None
|
self.content_dir: Path = None
|
||||||
self.templates_dir: Path = None
|
self.templates_dir: Path = None
|
||||||
self.styles_dir: Path = None
|
self.styles_dir: Path = None
|
||||||
|
|
||||||
|
self.listen_address: str = "127.0.0.1"
|
||||||
|
self.listen_port: int = 8080
|
||||||
|
self.debug: bool = False
|
||||||
|
self.access_log: bool = True
|
||||||
|
self.max_threads: int = 4
|
||||||
|
self.admin_browser: bool = False
|
||||||
|
self.admin_password: str = None
|
||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
try:
|
try:
|
||||||
with open(self.config_path, "rb") as f:
|
with open(self.config_path, "rb") as f:
|
||||||
@ -41,6 +50,18 @@ class Configuration:
|
|||||||
raise ValueError("Config file does not contain styles_dir path")
|
raise ValueError("Config file does not contain styles_dir path")
|
||||||
self.styles_dir = Path(self.styles_dir)
|
self.styles_dir = Path(self.styles_dir)
|
||||||
|
|
||||||
|
server = self.config_data.get("server", {})
|
||||||
|
if not server:
|
||||||
|
raise ValueError("Config file does not contain server section")
|
||||||
|
|
||||||
|
self.listen_address = server.get("listen_address", self.listen_address)
|
||||||
|
self.listen_port = server.get("listen_port", self.listen_port)
|
||||||
|
self.debug = server.get("debug", self.debug)
|
||||||
|
self.access_log = server.get("access_log", self.access_log)
|
||||||
|
self.max_threads = server.get("max_threads", self.max_threads)
|
||||||
|
self.admin_browser = server.get("admin_browser", self.admin_browser)
|
||||||
|
self.admin_password = server.get("admin_password", self.admin_password)
|
||||||
|
|
||||||
def set_globals(self):
|
def set_globals(self):
|
||||||
global CONTENT_DIR, TEMPLATES_DIR, STYLES_DIR
|
global CONTENT_DIR, TEMPLATES_DIR, STYLES_DIR
|
||||||
CONTENT_DIR = self.content_dir
|
CONTENT_DIR = self.content_dir
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from src.config.config import Configuration
|
from src.config.config import Configuration
|
||||||
from src.rendering import GENERIC_FILE_MAPPING
|
from src.rendering import GENERIC_FILE_MAPPING
|
||||||
from src.rendering.markdown import render_markdown, read_raw_markdown, rendered_markdown_to_plain_text
|
from src.rendering.markdown import (
|
||||||
|
render_markdown,
|
||||||
|
read_raw_markdown,
|
||||||
|
rendered_markdown_to_plain_text,
|
||||||
|
)
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
@ -16,9 +20,22 @@ class ImageMetadata:
|
|||||||
alt: str
|
alt: str
|
||||||
exif: dict
|
exif: dict
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MarkdownMetadata:
|
class MarkdownMetadata:
|
||||||
fontmatter: dict
|
"""
|
||||||
|
A class to represent metadata for a Markdown file.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
----------
|
||||||
|
frontmatter : dict
|
||||||
|
A dictionary containing the front matter of the Markdown file.
|
||||||
|
content : str
|
||||||
|
The main content of the Markdown file.
|
||||||
|
preview : str
|
||||||
|
A preview or summary of the Markdown content.
|
||||||
|
"""
|
||||||
|
frontmatter: dict
|
||||||
content: str
|
content: str
|
||||||
preview: str
|
preview: str
|
||||||
|
|
||||||
@ -30,6 +47,24 @@ class FileMetadata:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TemplateFile:
|
class TemplateFile:
|
||||||
|
"""
|
||||||
|
A class to represent a template file with its associated metadata.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
----------
|
||||||
|
name (str): The name of the file.
|
||||||
|
path (str): The file path.
|
||||||
|
proper_name (str): The proper name of the file.
|
||||||
|
extension (str): The file extension.
|
||||||
|
categories (list[str]): A list of categories associated with the file.
|
||||||
|
date_modified (str): The date the file was last modified.
|
||||||
|
date_created (str): The date the file was created.
|
||||||
|
size_kb (int): The size of the file in kilobytes.
|
||||||
|
metadata (ImageMetadata | FileMetadata | None): Metadata associated with the file,
|
||||||
|
which can be either image metadata, file metadata, or None.
|
||||||
|
dir_item_count (int): The number of items in the directory if the file is a directory.
|
||||||
|
is_dir (bool): A flag indicating whether the file is a directory.
|
||||||
|
"""
|
||||||
name: str
|
name: str
|
||||||
path: str
|
path: str
|
||||||
proper_name: str
|
proper_name: str
|
||||||
@ -51,9 +86,10 @@ class TemplateHelpers:
|
|||||||
def __init__(self, config: Configuration):
|
def __init__(self, config: Configuration):
|
||||||
self.config: Configuration = config
|
self.config: Configuration = config
|
||||||
|
|
||||||
|
def _filter_hidden_files(self, files):
|
||||||
|
return [f for f in files if not f.name.startswith("___")]
|
||||||
|
|
||||||
def build_metadata_for_file(self, path: str, categories: list[str] = []):
|
def _build_metadata_for_file(self, path: str, categories: list[str] = []):
|
||||||
"""Builds metadata for a file"""
|
|
||||||
file_path = self.config.content_dir / path
|
file_path = self.config.content_dir / path
|
||||||
for k in categories:
|
for k in categories:
|
||||||
if k == "image":
|
if k == "image":
|
||||||
@ -75,19 +111,37 @@ class TemplateHelpers:
|
|||||||
ret = FileMetadata(None)
|
ret = FileMetadata(None)
|
||||||
if file_path.suffix[1:].lower() == "md":
|
if file_path.suffix[1:].lower() == "md":
|
||||||
ret.typeMeta = MarkdownMetadata({}, "", "")
|
ret.typeMeta = MarkdownMetadata({}, "", "")
|
||||||
ret.typeMeta.fontmatter = frontmatter.load(file_path)
|
ret.typeMeta.frontmatter = frontmatter.load(file_path)
|
||||||
ret.typeMeta.content = render_markdown(file_path)
|
ret.typeMeta.content = render_markdown(file_path)
|
||||||
ret.typeMeta.rawContent = read_raw_markdown(file_path)
|
ret.typeMeta.rawContent = read_raw_markdown(file_path)
|
||||||
ret.typeMeta.rawText = rendered_markdown_to_plain_text(ret.typeMeta.content)
|
ret.typeMeta.rawText = rendered_markdown_to_plain_text(
|
||||||
|
ret.typeMeta.content
|
||||||
|
)
|
||||||
ret.typeMeta.preview = ret.typeMeta.rawText[:500] + "..."
|
ret.typeMeta.preview = ret.typeMeta.rawText[:500] + "..."
|
||||||
return ret
|
return ret
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_folder_contents(self, path: str = ""):
|
def get_folder_contents(self, path: str = ""):
|
||||||
"""Returns the contents of a folder as a list of TemplateFile objects
|
"""
|
||||||
|
Retrieve the contents of a folder and return a list of TemplateFile objects.
|
||||||
|
|
||||||
The metadata field is populated with the appropriate metadata object
|
Args:
|
||||||
|
path (str): The relative path to the folder within the content directory. Defaults to an empty string,
|
||||||
|
which refers to the root content directory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: A list of TemplateFile objects representing the files and directories within the specified folder.
|
||||||
|
|
||||||
|
The function performs the following steps:
|
||||||
|
1. Constructs the full path to the folder by combining the content directory with the provided path.
|
||||||
|
2. Retrieves all files and directories within the specified folder.
|
||||||
|
3. Iterates over each file and directory, creating a TemplateFile object with metadata such as name,
|
||||||
|
path, proper name, extension, categories, date modified, date created, size in KB, metadata, directory
|
||||||
|
item count, and whether it is a directory.
|
||||||
|
4. If the item is a file, it assigns categories based on the file extension using a predefined mapping.
|
||||||
|
5. Builds additional metadata for each file.
|
||||||
|
6. Filters out hidden files from the list.
|
||||||
|
7. Returns the list of TemplateFile objects.
|
||||||
"""
|
"""
|
||||||
search_contnet_path = self.config.content_dir / path
|
search_contnet_path = self.config.content_dir / path
|
||||||
files = search_contnet_path.glob("*")
|
files = search_contnet_path.glob("*")
|
||||||
@ -110,30 +164,70 @@ class TemplateHelpers:
|
|||||||
for k, v in GENERIC_FILE_MAPPING.items():
|
for k, v in GENERIC_FILE_MAPPING.items():
|
||||||
if f.suffix[1:].lower() in v:
|
if f.suffix[1:].lower() in v:
|
||||||
t.categories.append(k)
|
t.categories.append(k)
|
||||||
t.metadata = self.build_metadata_for_file(f, t.categories)
|
t.metadata = self._build_metadata_for_file(f, t.categories)
|
||||||
ret.append(t)
|
ret.append(t)
|
||||||
|
ret = self._filter_hidden_files(ret)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def get_sibling_content_files(self, path: str = ""):
|
def get_sibling_content_files(self, path: str = ""):
|
||||||
|
"""
|
||||||
|
Retrieves a list of sibling content files in the specified directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): The relative path within the content directory to search for files.
|
||||||
|
Defaults to an empty string, which means the root of the content directory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: A list of tuples, where each tuple contains the file name and its relative path
|
||||||
|
to the content directory. Only files that do not start with "___" are included.
|
||||||
|
"""
|
||||||
search_contnet_path = self.config.content_dir / path
|
search_contnet_path = self.config.content_dir / path
|
||||||
files = search_contnet_path.glob("*")
|
files = search_contnet_path.glob("*")
|
||||||
return [
|
return [
|
||||||
(file.name, str(file.relative_to(self.config.content_dir)))
|
(file.name, str(file.relative_to(self.config.content_dir)))
|
||||||
for file in files
|
for file in files
|
||||||
if file.is_file()
|
if file.is_file() and not file.name.startswith("___")
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_text_document_preview(self, path: str):
|
def get_text_document_preview(self, path: str):
|
||||||
|
"""
|
||||||
|
Generates a preview of the text document located at the given path.
|
||||||
|
|
||||||
|
This method reads the first 100 characters from the specified text file
|
||||||
|
and returns it as a string. The file path is constructed by combining
|
||||||
|
the content directory from the configuration with the provided path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): The relative path to the text document within the content directory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A string containing the first 100 characters of the text document.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FileNotFoundError: If the file at the specified path does not exist.
|
||||||
|
IOError: If an I/O error occurs while reading the file.
|
||||||
|
"""
|
||||||
file_path = self.config.content_dir / path
|
file_path = self.config.content_dir / path
|
||||||
with open(file_path, "r") as f:
|
with open(file_path, "r") as f:
|
||||||
content = f.read(100)
|
content = f.read(100)
|
||||||
return content
|
return content
|
||||||
|
|
||||||
def get_sibling_content_folders(self, path: str = ""):
|
def get_sibling_content_folders(self, path: str = ""):
|
||||||
|
"""
|
||||||
|
Retrieves a list of sibling content folders within a specified directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): A relative path from the content directory to search within. Defaults to an empty string,
|
||||||
|
which means the search will be conducted in the content directory itself.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list of tuple: A list of tuples where each tuple contains the folder name and its relative path
|
||||||
|
to the content directory. Only directories that do not start with "___" are included.
|
||||||
|
"""
|
||||||
search_contnet_path = self.config.content_dir / path
|
search_contnet_path = self.config.content_dir / path
|
||||||
files = search_contnet_path.glob("*")
|
files = search_contnet_path.glob("*")
|
||||||
return [
|
return [
|
||||||
(file.name, str(file.relative_to(self.config.content_dir)))
|
(file.name, str(file.relative_to(self.config.content_dir)))
|
||||||
for file in files
|
for file in files
|
||||||
if file.is_dir()
|
if file.is_dir() and not file.name.startswith("___")
|
||||||
]
|
]
|
||||||
|
@ -95,6 +95,30 @@ def render_page(
|
|||||||
template_path: Path = Path("./"),
|
template_path: Path = Path("./"),
|
||||||
style_path: Path = Path("./"),
|
style_path: Path = Path("./"),
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Renders a web page based on the provided path and optional base, template, and style paths.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (Path): The path to the target file or directory to render.
|
||||||
|
base_path (Path, optional): The base path to use for relative paths. Defaults to Path("./").
|
||||||
|
template_path (Path, optional): The path to the directory containing HTML templates. Defaults to Path("./").
|
||||||
|
style_path (Path, optional): The path to the directory containing CSS styles. Defaults to Path("./").
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The rendered HTML content of the page, or an error page if the target path does not exist or no suitable template is found.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: If the base template (base.html) is not found in the template_path.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- If the target path does not exist, a 404 error page is rendered.
|
||||||
|
- If the target path is a file, the function attempts to determine its type, category, and extension.
|
||||||
|
- The function generates a list of possible CSS styles based on the target path and its type/category.
|
||||||
|
- The function searches for suitable HTML templates based on the target path and its type/category.
|
||||||
|
- If no suitable template is found, the function either sends the file directly (if it's a file) or renders a 404 error page.
|
||||||
|
- If the target file is a document, its content is rendered as Markdown.
|
||||||
|
- The function ensures that the base template (base.html) exists before rendering the final content.
|
||||||
|
"""
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
return render_error_page(
|
return render_error_page(
|
||||||
error_code=404,
|
error_code=404,
|
||||||
@ -111,7 +135,18 @@ def render_page(
|
|||||||
relative_path = target_file.relative_to(base_path)
|
relative_path = target_file.relative_to(base_path)
|
||||||
relative_dir = target_path.relative_to(base_path)
|
relative_dir = target_path.relative_to(base_path)
|
||||||
|
|
||||||
# Generate the possible paths for style
|
"""
|
||||||
|
The styles are ordered in the following manner:
|
||||||
|
|
||||||
|
Specific style for the target path (e.g., /path/to/target.css).
|
||||||
|
Specific styles for the type and extension in the current and parent directories
|
||||||
|
(e.g., /path/to/__file.html.css).
|
||||||
|
Specific styles for the type and category in the current and parent directories
|
||||||
|
(e.g., /path/to/__file.document.css).
|
||||||
|
Base style (/base.css).
|
||||||
|
This ordering ensures that the most specific styles are applied first, followed by
|
||||||
|
more general styles, and finally the base style.
|
||||||
|
"""
|
||||||
styles = []
|
styles = []
|
||||||
styles.append("/" + str(relative_path) + ".css")
|
styles.append("/" + str(relative_path) + ".css")
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ class RouteManager:
|
|||||||
def __init__(self, config: Configuration):
|
def __init__(self, config: Configuration):
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
|
|
||||||
def _validate_and_sanitize_path(self, base_dir, requested_path):
|
def _validate_and_sanitize_path(self, base_dir, requested_path):
|
||||||
"""
|
"""
|
||||||
Validate and sanitize the requested path to ensure it does not traverse above the base directory.
|
Validate and sanitize the requested path to ensure it does not traverse above the base directory.
|
||||||
@ -21,11 +20,11 @@ class RouteManager:
|
|||||||
:return: A secure version of the requested path if valid, otherwise None.
|
:return: A secure version of the requested path if valid, otherwise None.
|
||||||
"""
|
"""
|
||||||
# Normalize both paths
|
# Normalize both paths
|
||||||
base_dir = os.path.abspath(base_dir)
|
base_dir = Path(base_dir)
|
||||||
requested_path = os.path.abspath(requested_path)
|
requested_path: Path = base_dir / requested_path
|
||||||
|
|
||||||
# Check if the requested path is within the base directory
|
# Check if the requested path is within the base directory
|
||||||
if not requested_path.startswith(base_dir):
|
if requested_path < base_dir:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Ensure the path does not contain any '..' or '.' components
|
# Ensure the path does not contain any '..' or '.' components
|
||||||
@ -33,32 +32,33 @@ class RouteManager:
|
|||||||
secure_path_parts = secure_path.split(os.sep)
|
secure_path_parts = secure_path.split(os.sep)
|
||||||
|
|
||||||
for part in secure_path_parts:
|
for part in secure_path_parts:
|
||||||
if part == '.' or part == '..':
|
if part == "." or part == "..":
|
||||||
|
print("Illegal path nice try")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Reconstruct the secure path
|
# Reconstruct the secure path
|
||||||
secure_path = os.path.join(base_dir, *secure_path_parts)
|
secure_path = os.path.join(base_dir, *secure_path_parts)
|
||||||
|
secure_path = Path(secure_path)
|
||||||
|
|
||||||
|
# Check if path exists
|
||||||
|
if not secure_path.exists():
|
||||||
|
raise Exception("Illegal path")
|
||||||
|
|
||||||
|
for part in secure_path.parts:
|
||||||
|
if part.startswith("___"):
|
||||||
|
print("hidden file")
|
||||||
|
raise Exception("Illegal path")
|
||||||
|
|
||||||
return secure_path
|
return secure_path
|
||||||
|
|
||||||
def _ensure_route(self, path: str):
|
def _ensure_route(self, path: str):
|
||||||
"""
|
|
||||||
Escapes the path for anything like
|
|
||||||
a path execution or injection attack
|
|
||||||
evaluates the path and ensures that it it does not
|
|
||||||
go above the self.content.content_dir
|
|
||||||
If any part of the path contains __, __{foldername}, or __{filename},
|
|
||||||
that is a hidden file or folder and should raise an exception
|
|
||||||
Any illegal path should raise an exception
|
|
||||||
"""
|
|
||||||
file_path: Path = self.config.content_dir / (path if path else "index.md")
|
file_path: Path = self.config.content_dir / (path if path else "index.md")
|
||||||
if file_path < self.config.content_dir:
|
if file_path < self.config.content_dir:
|
||||||
raise Exception("Illegal path")
|
raise Exception("Illegal path")
|
||||||
|
|
||||||
for part in file_path.parts:
|
if not self._validate_and_sanitize_path(
|
||||||
if part.startswith("__"):
|
self.config.content_dir, str(file_path)
|
||||||
raise Exception("Illegal path")
|
):
|
||||||
|
|
||||||
if not self._validate_and_sanitize_path(self.config.content_dir, str(file_path)):
|
|
||||||
raise Exception("Illegal path")
|
raise Exception("Illegal path")
|
||||||
|
|
||||||
def default_route(self, path: str):
|
def default_route(self, path: str):
|
||||||
@ -80,6 +80,15 @@ class RouteManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_style(self, path: str):
|
def get_style(self, path: str):
|
||||||
|
try:
|
||||||
|
self._validate_and_sanitize_path(self.config.styles_dir, path)
|
||||||
|
except Exception as e:
|
||||||
|
return render_error_page(
|
||||||
|
404,
|
||||||
|
"Not Found",
|
||||||
|
f"The requested resource was not found on this server. {e}",
|
||||||
|
self.config.templates_dir,
|
||||||
|
)
|
||||||
file_path: Path = self.config.styles_dir / path
|
file_path: Path = self.config.styles_dir / path
|
||||||
if file_path.exists():
|
if file_path.exists():
|
||||||
return send_file(file_path)
|
return send_file(file_path)
|
||||||
@ -91,8 +100,16 @@ class RouteManager:
|
|||||||
self.config.templates_dir,
|
self.config.templates_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
@lru_cache(maxsize=None)
|
|
||||||
def get_static(self, path: str):
|
def get_static(self, path: str):
|
||||||
|
try:
|
||||||
|
self._validate_and_sanitize_path(self.config.content_dir, path)
|
||||||
|
except Exception as e:
|
||||||
|
return render_error_page(
|
||||||
|
404,
|
||||||
|
"Not Found",
|
||||||
|
"The requested resource was not found on this server.",
|
||||||
|
self.config.templates_dir,
|
||||||
|
)
|
||||||
file_path: Path = self.config.content_dir / path
|
file_path: Path = self.config.content_dir / path
|
||||||
if file_path.exists():
|
if file_path.exists():
|
||||||
# Check to see if the file is an image, if it is, render a thumbnail
|
# Check to see if the file is an image, if it is, render a thumbnail
|
||||||
|
@ -13,8 +13,8 @@ class Server(BaseApplication):
|
|||||||
host: str = "0.0.0.0",
|
host: str = "0.0.0.0",
|
||||||
port: int = 8080,
|
port: int = 8080,
|
||||||
template_functions: Dict[str, Callable] = None,
|
template_functions: Dict[str, Callable] = None,
|
||||||
enable_admin_browser: bool = False,
|
|
||||||
workers: int = multiprocessing.cpu_count() // 2 + 1,
|
workers: int = multiprocessing.cpu_count() // 2 + 1,
|
||||||
|
access_log: bool = True,
|
||||||
options=None,
|
options=None,
|
||||||
):
|
):
|
||||||
if template_functions is None:
|
if template_functions is None:
|
||||||
@ -28,9 +28,9 @@ class Server(BaseApplication):
|
|||||||
self.app.secret_key = "your_secret_key"
|
self.app.secret_key = "your_secret_key"
|
||||||
self.options = options or {
|
self.options = options or {
|
||||||
"bind": f"{self.host}:{self.port}",
|
"bind": f"{self.host}:{self.port}",
|
||||||
"reload": True, # Enable automatic reloading
|
"reload": self.debug,
|
||||||
"threads": workers,
|
"threads": workers,
|
||||||
"accesslog": "-",
|
"accesslog": "-" if access_log else None,
|
||||||
}
|
}
|
||||||
for name, func in template_functions.items():
|
for name, func in template_functions.items():
|
||||||
self.register_template_function(name, func)
|
self.register_template_function(name, func)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user