diff options
Diffstat (limited to 'main.py')
| -rw-r--r-- | main.py | 128 |
1 files changed, 110 insertions, 18 deletions
@@ -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 |
