summaryrefslogtreecommitdiff
path: root/main.py
diff options
context:
space:
mode:
authoraltaf-creator <dev@altafcreator.com>2026-06-19 22:34:06 +0800
committeraltaf-creator <dev@altafcreator.com>2026-06-19 22:34:06 +0800
commitaee87b3ec0e8487101f506f229d1f5acf6245856 (patch)
tree798cc7ba57f6d6564ce67a1b3e30a1549ed265d8 /main.py
parent3525abf99fa3e6f41028cb7e93c8e58eb3f0a9c6 (diff)
minimum working product
Diffstat (limited to 'main.py')
-rw-r--r--main.py128
1 files changed, 110 insertions, 18 deletions
diff --git a/main.py b/main.py
index dae6661..f9693b5 100644
--- a/main.py
+++ b/main.py
@@ -1,11 +1,14 @@
+# files.altafcreator.com is a READ-ONLY website of files I want to share.
+# This code is not safe for user-uploaded files.
+
import fastapi
from fastapi.middleware.cors import CORSMiddleware
import fastapi.staticfiles
import fastapi.responses
-from pydantic import BaseModel
from pathlib import Path
-import os
import html
+from bs4 import BeautifulSoup
+import datetime
print("Hello, world!")
@@ -29,36 +32,125 @@ app.add_middleware(
)
+HTML_FOLDER_TEMPLATE = ""
+with open("index.html") as f:
+ HTML_FOLDER_TEMPLATE = f.read()
+
+
+@app.middleware("http")
+async def force_trailing_slash(request: fastapi.Request, call_next):
+ path = request.url.path
+
+ if not path.endswith("/") and not Path(path).suffix:
+ new_url = str(request.url.replace(path=path + "/"))
+ return fastapi.responses.RedirectResponse(url=new_url, status_code=301)
+
+ response = await call_next(request)
+ return response
+
+
@app.get("/{path:path}")
def folder(path: str):
target_path = (FOLDER_PATH / path).resolve()
- if FOLDER_PATH not in target_path.parents and target_path != FOLDER_PATH:
+ if not target_path.is_relative_to(FOLDER_PATH):
return fastapi.responses.Response(status_code=403, content="Access denied.")
- is_file = False
-
if target_path.is_file():
- is_file = True
+# if target_path.suffix == ".md":
+# return fastapi.responses.Response(content=markdown(target_path), media_type="text/html", status_code=200)
return fastapi.responses.FileResponse(target_path)
elif not target_path.is_dir():
return fastapi.responses.Response(status_code=404)
- content = f"<p>/{path}</p><a href='..'>../</a><br>"
+ files = []
+ directories = []
for item in sorted(target_path.iterdir()):
- safe_child_path = html.escape(item.name)
-
- href_path = ""
- if path == "":
- href_path = f"/{safe_child_path}"
+ if (target_path / item.name).resolve().is_file():
+ files.append(item.name)
else:
- href_path = f"/{path.rstrip('/')}/{safe_child_path}"
+ directories.append(item.name)
+
+ soup = BeautifulSoup(HTML_FOLDER_TEMPLATE, "html.parser")
+
+ for d in directories:
+ add_item_html(d, path, True, soup)
+ for f in files:
+ add_item_html(f, path, False, soup)
+
+ local_path_list = path.split("/")
+
+ home_btn = soup.new_tag("a")
+ home_btn["class"] = "breadcrumb-button"
+ home_btn["href"] = "/"
+ home_btn.string = "🏠 altaf-files"
+ soup.select_one("#breadcrumb-container").append(home_btn)
+
+ for i in range(len(local_path_list)):
+ new_sep = soup.new_tag("span")
+ new_sep.string = "/"
+ soup.select_one("#breadcrumb-container").append(new_sep)
+
+ new_btn = soup.new_tag("a")
+ new_btn["class"] = "breadcrumb-button"
+ new_btn["href"] = "/" + "/".join(local_path_list[0:i + 1])
+ new_btn.string = local_path_list[i]
+ soup.select_one("#breadcrumb-container").append(new_btn)
+
+ return fastapi.responses.Response(content=str(soup), media_type="text/html", status_code=200)
+
+
+def markdown(absolute_path: str):
+ pass
+
+
+def add_item_html(child_path: str, current_path: str, is_directory: bool, soup: BeautifulSoup):
+ href_path = ""
+
+ if current_path == "":
+ href_path = f"/{child_path}"
+ else:
+ href_path = f"/{current_path.rstrip('/')}/{child_path}"
+
+ symbol = "📄"
+ if is_directory:
+ symbol = "📂"
+
+ absolute_path = Path(f"{str(FOLDER_PATH).rstrip('/')}/{current_path.rstrip('/')}/{child_path}").resolve()
+
+ if not absolute_path.exists():
+ return ""
+
+ size = "—"
+ if not is_directory:
+ size = format_size(absolute_path.stat().st_size)
+
+ date_modified = str(datetime.datetime.fromtimestamp(absolute_path.stat().st_mtime))[:10].replace("-", "/")
+
+ new_btn = soup.new_tag("a")
+ new_btn["href"] = href_path
+
+ new_div = soup.new_tag("div")
+ new_btn.append(new_div)
+
+ new_span_name = soup.new_tag("span")
+ new_span_name.string = f"{symbol} {child_path}"
+ new_div.append(new_span_name)
+ new_span_date = soup.new_tag("span")
+ new_span_date["class"] = "list-metadata list-date"
+ new_div.append(new_span_date)
+ new_span_date.string = date_modified
+ new_span_size = soup.new_tag("span")
+ new_span_size["class"] = "list-metadata"
+ new_span_size.string = size
+ new_div.append(new_span_size)
- filetype_string = "📂"
- if (target_path / safe_child_path).resolve().is_file():
- filetype_string = "📄"
+ soup.select_one("#list-container").append(new_btn)
- content += f"<a href='{href_path}'>{filetype_string} {safe_child_path}</a><br>"
- return fastapi.responses.Response(content=content, media_type="text/html", status_code=200)
+def format_size(byte_size):
+ for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB']:
+ if byte_size < 1024.0:
+ return f"{round(byte_size, 1)} {unit}"
+ byte_size /= 1024.0