generated from hjess/PythonTemplateProject
Lets test
All checks were successful
Build, Push, and Deploy to Nomad / docker-nomad (push) Successful in 34s
All checks were successful
Build, Push, and Deploy to Nomad / docker-nomad (push) Successful in 34s
This commit is contained in:
224
app.py
224
app.py
@@ -1,144 +1,100 @@
|
|||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
import json
|
|
||||||
import os
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
import json
|
||||||
|
import os
|
||||||
from markdown_render import render_markdown_with_jinja
|
from markdown_render import render_markdown_with_jinja
|
||||||
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
|
|
||||||
|
|
||||||
|
|
||||||
|
class App:
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the FastAPI app."""
|
||||||
|
self.app = FastAPI(lifespan=self.lifespan)
|
||||||
|
self.templates = Jinja2Templates(directory="templates")
|
||||||
|
self.data = self.load_mock_data()
|
||||||
|
|
||||||
|
# Mount directories
|
||||||
|
self.app.mount("/data", StaticFiles(directory="data"), name="data")
|
||||||
|
self.app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||||
|
|
||||||
|
# Add routes
|
||||||
|
self.add_routes()
|
||||||
|
|
||||||
|
# 1. Lifespan events
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(self, app: FastAPI):
|
||||||
|
print("App startup: Processing Markdown files...")
|
||||||
|
self.process_markdown_files("./data", "./data") # Process all Markdown files
|
||||||
|
print("Markdown processing complete!")
|
||||||
|
yield # Allow the app to start
|
||||||
|
print("App shutdown: Cleanup complete.")
|
||||||
|
|
||||||
|
# 2. Load JSON data
|
||||||
|
def load_mock_data(self):
|
||||||
|
"""Load mock data from a JSON file."""
|
||||||
|
with open("mock_data.json") as file:
|
||||||
|
return json.load(file)
|
||||||
|
|
||||||
|
# 3. Markdown processing logic
|
||||||
|
@staticmethod
|
||||||
|
def process_markdown_files(input_dir: str, output_dir: str):
|
||||||
|
"""
|
||||||
|
Recursively process all Markdown files in the input directory,
|
||||||
|
render them to HTML, and save them in the output directory.
|
||||||
|
"""
|
||||||
|
for root, _, files in os.walk(input_dir):
|
||||||
|
for file in files:
|
||||||
|
if file.endswith(".md"):
|
||||||
|
input_file_path = os.path.join(root, file)
|
||||||
|
relative_path = os.path.relpath(input_file_path, input_dir)
|
||||||
|
output_file_path = os.path.join(output_dir, os.path.splitext(relative_path)[0] + ".html")
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
|
||||||
|
|
||||||
|
with open(input_file_path, "r", encoding="utf-8") as md_file:
|
||||||
|
markdown_content = md_file.read()
|
||||||
|
|
||||||
|
print(f"Processing: {input_file_path} -> {output_file_path}")
|
||||||
|
rendered_html = render_markdown_with_jinja(markdown_content)
|
||||||
|
|
||||||
|
with open(output_file_path, "w", encoding="utf-8") as html_file:
|
||||||
|
html_file.write(rendered_html)
|
||||||
|
|
||||||
|
# 4. Routes
|
||||||
|
def add_routes(self):
|
||||||
|
"""Add all routes to the FastAPI app."""
|
||||||
|
@self.app.get("/", response_class=HTMLResponse)
|
||||||
|
async def get_index(request: Request):
|
||||||
|
"""Index route."""
|
||||||
|
return self.templates.TemplateResponse(
|
||||||
|
"index.html",
|
||||||
|
{"request": request, "data": self.data, "page_title": "Forside", "author": "Henrik"},
|
||||||
|
)
|
||||||
|
|
||||||
|
@self.app.get("/category/{category_name}", response_class=HTMLResponse)
|
||||||
|
async def get_category(request: Request, category_name: str):
|
||||||
|
"""Category route."""
|
||||||
|
category = next((cat for cat in self.data["categories"] if cat["path"] == category_name), None)
|
||||||
|
if category:
|
||||||
|
category_file = f"data/{category_name}/index.html"
|
||||||
|
if os.path.exists(category_file):
|
||||||
|
with open(category_file) as file:
|
||||||
|
category_content = file.read()
|
||||||
|
return self.templates.TemplateResponse(
|
||||||
|
"category.html",
|
||||||
|
{
|
||||||
|
"request": request,
|
||||||
|
"data": self.data,
|
||||||
|
"page_title": category["name"],
|
||||||
|
"author": category["author"],
|
||||||
|
"content": category_content,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return HTMLResponse("Kategori ikke fundet", status_code=404)
|
||||||
|
|
||||||
|
|
||||||
|
# Create the app instance
|
||||||
# Context manager for app lifespan
|
app_instance = App()
|
||||||
@asynccontextmanager
|
app = app_instance.app
|
||||||
async def lifespan(app: FastAPI):
|
|
||||||
print("App startup: Processing Markdown files...")
|
|
||||||
process_markdown_files("./data", "./data") # Process all Markdown files
|
|
||||||
print("Markdown processing complete!")
|
|
||||||
yield # Allow the app to start
|
|
||||||
print("App shutdown: Cleanup complete.")
|
|
||||||
|
|
||||||
app = FastAPI(lifespan=lifespan)
|
|
||||||
app.mount("/data", StaticFiles(directory="data"), name="data")
|
|
||||||
|
|
||||||
|
|
||||||
# Mount static files
|
|
||||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
||||||
|
|
||||||
|
|
||||||
# Templates directory
|
|
||||||
templates = Jinja2Templates(directory="templates")
|
|
||||||
|
|
||||||
# Load JSON data
|
|
||||||
with open("mock_data.json") as file:
|
|
||||||
data = json.load(file)
|
|
||||||
|
|
||||||
@app.get("/test", response_class=HTMLResponse)
|
|
||||||
async def home_test():
|
|
||||||
# Load the Markdown content from a file
|
|
||||||
with open("templates/example.md", "r") as f:
|
|
||||||
markdown_content = f.read()
|
|
||||||
|
|
||||||
# Render Markdown first, then inject Jinja2 components
|
|
||||||
rendered_html = render_markdown_with_jinja(markdown_content)
|
|
||||||
|
|
||||||
# Wrap in a base HTML layout
|
|
||||||
html_template = f"""
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Markdown + Jinja2</title>
|
|
||||||
<style>
|
|
||||||
.img-left-overlay img {{ width: 300px; }}
|
|
||||||
.box {{ border: 1px solid #ccc; padding: 10px; background-color: #f9f9f9; }}
|
|
||||||
.note {{ background-color: #e7f3fe; border-left: 4px solid #2196F3; padding: 10px; }}
|
|
||||||
.warning {{ background-color: #fff3cd; border-left: 4px solid #ffeb3b; padding: 10px; }}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="content">
|
|
||||||
{rendered_html}
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
"""
|
|
||||||
return HTMLResponse(content=html_template)
|
|
||||||
|
|
||||||
def process_markdown_files(input_dir: str, output_dir: str):
|
|
||||||
"""
|
|
||||||
Recursively process all Markdown files in the input directory,
|
|
||||||
render them to HTML, and save them in the output directory.
|
|
||||||
"""
|
|
||||||
for root, _, files in os.walk(input_dir):
|
|
||||||
for file in files:
|
|
||||||
if file.endswith(".md"):
|
|
||||||
input_file_path = os.path.join(root, file)
|
|
||||||
|
|
||||||
# Determine output file path (convert .md to .html)
|
|
||||||
relative_path = os.path.relpath(input_file_path, input_dir)
|
|
||||||
output_file_path = os.path.join(output_dir, os.path.splitext(relative_path)[0] + ".html")
|
|
||||||
|
|
||||||
# Ensure the output directory exists
|
|
||||||
os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
|
|
||||||
|
|
||||||
# Read Markdown content
|
|
||||||
with open(input_file_path, "r", encoding="utf-8") as md_file:
|
|
||||||
markdown_content = md_file.read()
|
|
||||||
|
|
||||||
# Render Markdown with Jinja2
|
|
||||||
print(f"Processing: {input_file_path} -> {output_file_path}")
|
|
||||||
rendered_html = render_markdown_with_jinja(markdown_content)
|
|
||||||
|
|
||||||
# Write the rendered HTML to the output file
|
|
||||||
with open(output_file_path, "w", encoding="utf-8") as html_file:
|
|
||||||
html_file.write(rendered_html)
|
|
||||||
|
|
||||||
|
|
||||||
# Index route
|
|
||||||
@app.get("/", response_class=HTMLResponse)
|
|
||||||
async def get_index(request: Request):
|
|
||||||
return templates.TemplateResponse(
|
|
||||||
"index.html",
|
|
||||||
{"request": request, "data": data, "page_title": "Forside", "author": "Henrik"}
|
|
||||||
)
|
|
||||||
|
|
||||||
@app.get("/sitemap", response_class=HTMLResponse)
|
|
||||||
async def sitemap():
|
|
||||||
"""Simple home page listing available HTML files."""
|
|
||||||
links = []
|
|
||||||
for root, _, files in os.walk("./data"):
|
|
||||||
for file in files:
|
|
||||||
if file.endswith(".html"):
|
|
||||||
relative_path = os.path.relpath(os.path.join(root, file), "./data")
|
|
||||||
link = f"<a href='/data/{relative_path}'>{relative_path}</a>"
|
|
||||||
links.append(link)
|
|
||||||
links_html = "<br>".join(links)
|
|
||||||
return HTMLResponse(content=f"<h1>Available Pages</h1>{links_html}")
|
|
||||||
|
|
||||||
# Category route
|
|
||||||
@app.get("/category/{category_name}", response_class=HTMLResponse)
|
|
||||||
async def get_category(request: Request, category_name: str):
|
|
||||||
# Find den korrekte kategori
|
|
||||||
category = next((cat for cat in data["categories"] if cat["path"] == category_name), None)
|
|
||||||
if category:
|
|
||||||
category_file = f"data/{category_name}/index.html"
|
|
||||||
if os.path.exists(category_file):
|
|
||||||
with open(category_file) as file:
|
|
||||||
category_content = file.read()
|
|
||||||
return templates.TemplateResponse(
|
|
||||||
"category.html",
|
|
||||||
{
|
|
||||||
"request": request,
|
|
||||||
"data": data,
|
|
||||||
"page_title": category["name"],
|
|
||||||
"author": category["author"],
|
|
||||||
"content": category_content
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return HTMLResponse("Kategori ikke fundet", status_code=404)
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
<p>PortugalFAQ - Henriks og Erikas lille side</p>
|
||||||
|
<p></p>
|
||||||
<h1>BoligBolig Bolig Bolig - Hvor skal sengen placeres</h1>
|
<h1>BoligBolig Bolig Bolig - Hvor skal sengen placeres</h1>
|
||||||
<p>Nu bliver det spænde!</p>
|
<p>Nu bliver det spænde!</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -5,3 +7,4 @@
|
|||||||
<p>Dette er stadig en test side</p>
|
<p>Dette er stadig en test side</p>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</p>
|
||||||
|
<p></p>
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
|
|
||||||
|
{% block title %}PortugalFAQ - Henriks og Erikas lille side{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
# BoligBolig Bolig Bolig - Hvor skal sengen placeres
|
# BoligBolig Bolig Bolig - Hvor skal sengen placeres
|
||||||
|
|
||||||
Nu bliver det spænde!
|
Nu bliver det spænde!
|
||||||
|
|
||||||
{{ note("Dette er stadig en test side") }}
|
{{ note("Dette er stadig en test side") }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
<title>{% block title %}PortugalFAQ{% endblock %}</title>
|
<title>{% block title %}PortugalFAQ{% endblock %}</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||||
<!-- <link rel="stylesheet" href="{{ url_for('static', path='css/main.css') }}"> -->
|
|
||||||
<link rel="stylesheet" href="/static/css/main.css">
|
<link rel="stylesheet" href="/static/css/main.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="is-preload">
|
<body class="is-preload">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<span class="image main">
|
<span class="image main">
|
||||||
<img src="{{ url_for('static', path='images/pic11.jpg') }}" alt="Portugal" />
|
<img src="static/images/pic11.jpg" alt="Portugal" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<hr class="major" />
|
<hr class="major" />
|
||||||
|
|||||||
Reference in New Issue
Block a user