Fix Docs Reader nested path links
This commit is contained in:
@@ -38,37 +38,44 @@ async def list_docs(req: Request):
|
||||
|
||||
# 1. Pinned Docs (from whitelist)
|
||||
pinned = []
|
||||
|
||||
pinned_paths = set()
|
||||
|
||||
for filename, title in ALLOWED_DOCS.items():
|
||||
# Check root level only for pinned items (simpler, or check recursively and pin first?)
|
||||
# Legacy behavior was pinned items are usually in root.
|
||||
# Let's verify existence.
|
||||
full_path = _find_file_recursive(base_path, filename)
|
||||
if full_path:
|
||||
# We want the relative path as the ID
|
||||
rel_path = os.path.relpath(full_path, base_path)
|
||||
pinned.append({"name": title, "file": rel_path})
|
||||
pinned_paths.add(rel_path)
|
||||
|
||||
# 2. All other docs (dynamic scan)
|
||||
library = []
|
||||
|
||||
# helper to check if already in pinned
|
||||
pinned_filenames = set()
|
||||
|
||||
for filename, title in ALLOWED_DOCS.items():
|
||||
full_path = _find_file(base_path, filename) # Helper now needs to look deeper?
|
||||
if full_path:
|
||||
pinned.append({"name": title, "file": filename})
|
||||
pinned_filenames.add(filename)
|
||||
|
||||
# Scan for all .md files recursively
|
||||
if os.path.exists(base_path):
|
||||
for root, dirs, files in os.walk(base_path):
|
||||
for file in files:
|
||||
if file.endswith(".md"):
|
||||
# Calculate relative path or just filename.
|
||||
# If we use just filename, distinct files with same name in diff folders conflict.
|
||||
# Current view_doc takes {filename}. Let's assume filenames are unique enough or we handle paths.
|
||||
# For now, let's just show them if they aren't pinned.
|
||||
full_path = os.path.join(root, file)
|
||||
rel_path = os.path.relpath(full_path, base_path)
|
||||
|
||||
if file not in pinned_filenames:
|
||||
# Try to get a nice name (Title from first line?) or filename
|
||||
name = file.replace(".md", "").replace("-", " ").title()
|
||||
library.append({"name": name, "file": file})
|
||||
if rel_path not in pinned_paths:
|
||||
# Improved Naming: File name + Parent Dir if nested
|
||||
# e.g. crumbcodex/README.md -> "Crumbcodex / Readme"
|
||||
parent = os.path.basename(root)
|
||||
safe_name = file.replace(".md", "").replace("-", " ").title()
|
||||
|
||||
if parent and parent != os.path.basename(base_path) and parent != "docs":
|
||||
# If deeper than root
|
||||
display_name = f"{parent.title()} / {safe_name}"
|
||||
else:
|
||||
display_name = safe_name
|
||||
|
||||
library.append({"name": display_name, "file": rel_path})
|
||||
|
||||
# Combine or separate? Let's just return all in 'docs' for now to fit the template expectation.
|
||||
# The template iterates 'docs'.
|
||||
|
||||
# Combine
|
||||
all_docs = pinned + sorted(library, key=lambda x: x["name"])
|
||||
|
||||
return req.app.state.render(
|
||||
@@ -78,27 +85,29 @@ async def list_docs(req: Request):
|
||||
page_title="Dokumentation"
|
||||
)
|
||||
|
||||
@router.get("/docs/{filename}", response_class=HTMLResponse)
|
||||
async def view_doc(req: Request, filename: str):
|
||||
@router.get("/docs/{file_path:path}", response_class=HTMLResponse)
|
||||
async def view_doc(req: Request, file_path: str):
|
||||
"""
|
||||
Render a specific markdown file. Now supports any MD file found.
|
||||
Render a specific markdown file. specific via relative path.
|
||||
"""
|
||||
# Security: basic check to prevent directory traversal outside allowable scope
|
||||
if ".." in filename or "/" in filename: # filename param is usually just the last part if caught by path param?
|
||||
# Actually FastAPI path param "{filename}" stops at slashes unless defined as "{path:path}".
|
||||
# So 'filename' here is just the leaf name.
|
||||
pass
|
||||
|
||||
# Security: Prevent traversal up
|
||||
if ".." in file_path:
|
||||
raise HTTPException(400, "Invalid path.")
|
||||
|
||||
base_path = _get_docs_base_path()
|
||||
full_path = os.path.join(base_path, file_path)
|
||||
|
||||
# Use recursive find
|
||||
file_path = _find_file_recursive(base_path, filename)
|
||||
|
||||
if not file_path:
|
||||
raise HTTPException(404, "File not on server.")
|
||||
if not os.path.exists(full_path) or not os.path.isfile(full_path):
|
||||
# Fallback: maybe it was a legacy link with just filename?
|
||||
# Try finding it recursively if direct path fails
|
||||
found = _find_file_recursive(base_path, os.path.basename(file_path))
|
||||
if found:
|
||||
full_path = found
|
||||
else:
|
||||
raise HTTPException(404, "File not on server.")
|
||||
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
with open(full_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
html_content = markdown.markdown(
|
||||
@@ -107,14 +116,20 @@ async def view_doc(req: Request, filename: str):
|
||||
)
|
||||
|
||||
# Determine Title
|
||||
title = ALLOWED_DOCS.get(filename, filename.replace(".md", "").replace("-", " ").title())
|
||||
filename = os.path.basename(full_path)
|
||||
# Check if pinned to get nice title
|
||||
title = filename.replace(".md", "").replace("-", " ").title()
|
||||
for k, v in ALLOWED_DOCS.items():
|
||||
if k == filename:
|
||||
title = v
|
||||
break
|
||||
|
||||
return req.app.state.render(
|
||||
req,
|
||||
"pages/doc_viewer.html",
|
||||
doc_title=title,
|
||||
doc_content=html_content,
|
||||
filename=filename
|
||||
filename=file_path # Keep full path for context? Or filename? Template uses it for back link maybe?
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user