uhhh lots of things
All checks were successful
Datadog Software Composition Analysis / Datadog SBOM Generation and Upload (push) Successful in 16s
Datadog Secrets Scanning / Datadog Static Analyzer (push) Successful in 14s
Datadog Static Analysis / Datadog Static Analyzer (push) Successful in 24s

This commit is contained in:
2025-03-08 11:17:24 -05:00
parent 0a6d5b8a90
commit c6f36d0408
7 changed files with 222 additions and 44 deletions

View File

@ -1,7 +1,11 @@
from dataclasses import dataclass
from src.config.config import Configuration
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 PIL import Image
@ -16,9 +20,22 @@ class ImageMetadata:
alt: str
exif: dict
@dataclass
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
preview: str
@ -30,6 +47,24 @@ class FileMetadata:
@dataclass
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
path: str
proper_name: str
@ -51,9 +86,10 @@ class TemplateHelpers:
def __init__(self, config: Configuration):
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] = []):
"""Builds metadata for a file"""
def _build_metadata_for_file(self, path: str, categories: list[str] = []):
file_path = self.config.content_dir / path
for k in categories:
if k == "image":
@ -75,19 +111,37 @@ class TemplateHelpers:
ret = FileMetadata(None)
if file_path.suffix[1:].lower() == "md":
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.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] + "..."
return ret
return None
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
files = search_contnet_path.glob("*")
@ -110,30 +164,70 @@ class TemplateHelpers:
for k, v in GENERIC_FILE_MAPPING.items():
if f.suffix[1:].lower() in v:
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 = self._filter_hidden_files(ret)
return ret
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
files = search_contnet_path.glob("*")
return [
(file.name, str(file.relative_to(self.config.content_dir)))
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):
"""
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
with open(file_path, "r") as f:
content = f.read(100)
return content
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
files = search_contnet_path.glob("*")
return [
(file.name, str(file.relative_to(self.config.content_dir)))
for file in files
if file.is_dir()
if file.is_dir() and not file.name.startswith("___")
]

View File

@ -95,6 +95,30 @@ def render_page(
template_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():
return render_error_page(
error_code=404,
@ -111,7 +135,18 @@ def render_page(
relative_path = target_file.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.append("/" + str(relative_path) + ".css")