diff --git a/app/auth.py b/app/auth.py index db3df500..c6a9f18b 100644 --- a/app/auth.py +++ b/app/auth.py @@ -1,5 +1,4 @@ # app/auth.py -# app/auth.py import os from functools import wraps diff --git a/app/frontend.py b/app/frontend.py index 9cc25798..ccbf9d9d 100644 --- a/app/frontend.py +++ b/app/frontend.py @@ -1,39 +1,30 @@ -# app/frontend.py (new file or inline in main.py) -from fastapi import APIRouter, Request, status -from fastapi.responses import FileResponse -from fastapi.staticfiles import StaticFiles -from app.auth import require_login +# app/frontend.py import os +from pathlib import Path +from fastapi import APIRouter, Request +from fastapi.templating import Jinja2Templates +from app.auth import require_login router = APIRouter() -# 1) Serve the folder that contains index.html, etc. -# e.g. "frontend" is relative to your project root -frontend_folder = os.path.join(os.path.dirname(__file__), "..", "frontend") +# Point templates_dir to "frontend/templates" +templates_dir = Path(__file__).parent.parent / "frontend" / "templates" +templates = Jinja2Templates(directory=str(templates_dir)) -# If you just want to serve the entire folder as static: -router.mount("/static", StaticFiles(directory=frontend_folder), name="static") +@router.get("/", include_in_schema=False) +async def serve_index(request: Request): + return templates.TemplateResponse("index.html", {"request": request}) -# 2) For the root route ("/"), return the index.html +@router.get("/about", include_in_schema=False) +async def serve_about(request: Request): + return templates.TemplateResponse("about.html", {"request": request}) -@router.get("/upload", response_class=FileResponse) +@router.get("/upload", include_in_schema=False) @require_login async def serve_upload(request: Request): - return os.path.join(frontend_folder, "upload.html") + return templates.TemplateResponse("upload.html", {"request": request}) -# 3) Serve favicon.ico from the frontend folder -@router.get("/favicon.ico", response_class=FileResponse) +@router.get("/favicon.ico", include_in_schema=False) def favicon(): - return os.path.join(frontend_folder, "favicon.ico") - -""" @router.exception_handler(404) -async def custom_404_handler(request: Request, exc): - return FileResponse("frontend/404.html", status_code=status.HTTP_404_NOT_FOUND) """ - -@router.get("/", response_class=FileResponse) -async def serve_index(request: Request): - return os.path.join(frontend_folder, "index.html") - -@router.get("/about", response_class=FileResponse) -async def serve_about(request: Request): - return os.path.join(frontend_folder, "about.html") \ No newline at end of file + # If you have a real favicon in `frontend/static/favicon.ico`, you could do: + return str(Path(__file__).parent.parent / "frontend" / "static" / "favicon.ico") diff --git a/app/main.py b/app/main.py index d255c451..16c6c6e3 100644 --- a/app/main.py +++ b/app/main.py @@ -3,10 +3,14 @@ import os from fastapi import FastAPI, HTTPException, UploadFile, File, status, Request from fastapi.responses import FileResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates from starlette.middleware.sessions import SessionMiddleware from starlette.config import Config from starlette.middleware.trustedhost import TrustedHostMiddleware from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware +from pathlib import Path + from app.database import init_db from app.config import settings from app.tasks.upload_to_s3 import upload_to_s3 @@ -14,13 +18,11 @@ from app.tasks.upload_to_dropbox import upload_to_dropbox from app.tasks.upload_to_paperless import upload_to_paperless from app.tasks.upload_to_nextcloud import upload_to_nextcloud from app.tasks.send_to_all import send_to_all_destinations -from pathlib import Path from app.api import router as api_router from app.frontend import router as frontend_router from app.auth import router as auth_router - # Load configuration from .env for the session key config = Config(".env") SESSION_SECRET = config( @@ -30,12 +32,10 @@ SESSION_SECRET = config( app = FastAPI(title="Document Processing API") - # 1) Session Middleware (for request.session to work) app.add_middleware(SessionMiddleware, secret_key=SESSION_SECRET) # 2) Respect the X-Forwarded-* headers from Traefik -# so your request.url_for(...) uses https://docparse.hosterra.net app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*") # 3) (Optional but recommended) Restrict valid hosts: @@ -45,12 +45,14 @@ app.add_middleware(TrustedHostMiddleware, allowed_hosts=[ "127.0.0.1" ]) +# Mount the static folder for CSS/JS: +frontend_static_dir = Path(__file__).parent.parent / "frontend" / "static" +app.mount("/static", StaticFiles(directory=frontend_static_dir), name="static") + @app.on_event("startup") def on_startup(): init_db() # Create tables if they don't exist - - @app.post("/process/") def process(file_path: str): """ @@ -166,10 +168,15 @@ async def ui_upload(file: UploadFile = File(...)): task = upload_to_s3.delay(target_path) return {"task_id": task.id, "status": "queued"} +# Custom 404 - we can still return the Jinja2 template, or the old static file: +# For a dynamic 404 using the base layout, see "frontend/404.html" usage below: @app.exception_handler(404) async def custom_404_handler(request: Request, exc: HTTPException): - return FileResponse( - "/app/frontend/404.html", + # Serve the 404 template directly + templates = Jinja2Templates(directory=str(frontend_static_dir.parent / "templates")) + return templates.TemplateResponse( + "404.html", + {"request": request}, status_code=status.HTTP_404_NOT_FOUND ) @@ -177,4 +184,3 @@ async def custom_404_handler(request: Request, exc: HTTPException): app.include_router(frontend_router) app.include_router(auth_router) app.include_router(api_router, prefix="/api") - diff --git a/frontend/404.html b/frontend/404.html deleted file mode 100644 index c085430d..00000000 --- a/frontend/404.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - 404 - Oops, DocuNova Lost the Page - - - - - - - - - -
-
-

404

-

Oops, we couldn’t find that page!

-

- It seems DocuNova has misplaced the document you were looking for. Whether it got lost in the cloud or hidden between the files, don’t worry – we’ve got your back. -

- - ← Return Home - -
-
- - - - - - - - diff --git a/frontend/about.html b/frontend/about.html deleted file mode 100644 index 718b8513..00000000 --- a/frontend/about.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - About DocuNova - - - - - - - - - -
-

About DocuNova

-

- Welcome to DocuNova – your modern, intelligent solution for document processing! We’ve built DocuNova to completely transform the way you handle your documents – from upload to extraction, from processing to storage. With cutting-edge technologies and a user-first design, DocuNova makes managing your documents as easy as a click. -

- - -
-

Our Story

-

- DocuNova was created with one goal in mind: to simplify and streamline document management for everyone, whether you’re a small startup or a large enterprise. Tired of clunky, outdated systems, we set out to design a platform that is intuitive, flexible, and packed with powerful features. -

-

- We harness the power of OpenAI for metadata extraction and text refinement, integrate seamlessly with Dropbox, Nextcloud, and Paperless NGX for storage and indexing, leverage Azure Document Intelligence for OCR, and even use Gotenberg for file-to-PDF conversions. And while we’ve implemented AWS S3 for now, we’re always evolving! -

-
- - -
-

Key Features

- -
- - -
-

Meet the Creator

-

- DocuNova is passionately developed by Christian Krakau-Louis, a visionary committed to solving real-world challenges with innovative technology. His dedication and expertise ensure that every feature in DocuNova is crafted with you in mind. -

-
- - -
-

Get Involved

-

- Want to dive into the code, contribute ideas, or simply check out the magic behind DocuNova? Visit our GitHub repository to see the project in action! -

- - GitHub Logo - View DocuNova on GitHub - -
-
- - - - - - - - diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index 6c183692..00000000 --- a/frontend/index.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - DocuNova - Intelligent Document Processing - - - - - - - - - -
-

Welcome to DocuNova

-

- Your intelligent solution for processing, managing, and organizing documents effortlessly. -

- -
-
-

Upload Documents

-

- Quickly upload and process your files with our user-friendly interface. -

- - Get Started → - -
-
-

Manage Your Files

-

- View, organize, and collaborate on your processed files in one central hub. -

- - View Files → - -
-
-
- - - - - - - - diff --git a/frontend/favicon.ico b/frontend/static/favicon.ico similarity index 100% rename from frontend/favicon.ico rename to frontend/static/favicon.ico diff --git a/frontend/static/js/common.js b/frontend/static/js/common.js new file mode 100644 index 00000000..985bdce6 --- /dev/null +++ b/frontend/static/js/common.js @@ -0,0 +1,46 @@ +// frontend/static/js/common.js + +(async function checkAuth() { + try { + const resp = await fetch("/api/whoami"); + if (resp.ok) { + const data = await resp.json(); + const authSection = document.getElementById("authSection"); + if (!authSection) return; + authSection.innerHTML = ''; + + const img = document.createElement('img'); + img.src = data.picture; + img.alt = 'User Avatar'; + img.className = 'inline-block h-8 w-8 rounded-full mr-2'; + + const textNode = document.createTextNode('Logged in as '); + const strong = document.createElement('strong'); + strong.textContent = data.email; + + const logoutLink = document.createElement('a'); + logoutLink.href = '/logout'; + logoutLink.className = 'ml-4 text-blue-600 hover:text-blue-800'; + logoutLink.textContent = 'Logout'; + + authSection.appendChild(img); + authSection.appendChild(textNode); + authSection.appendChild(strong); + authSection.appendChild(logoutLink); + } else { + const authSection = document.getElementById("authSection"); + if (authSection) { + authSection.innerHTML = + `Login`; + } + } + } catch (error) { + // Fallback if whoami endpoint fails + const authSection = document.getElementById("authSection"); + if (authSection) { + authSection.innerHTML = + `Login`; + } + } + })(); + \ No newline at end of file diff --git a/frontend/static/styles.css b/frontend/static/styles.css new file mode 100644 index 00000000..7d0a25ca --- /dev/null +++ b/frontend/static/styles.css @@ -0,0 +1,6 @@ +/* frontend/static/styles.css */ +/* Example overrides or additional styling */ +body { + /* Your global overrides can go here if needed */ + } + \ No newline at end of file diff --git a/frontend/templates/404.html b/frontend/templates/404.html new file mode 100644 index 00000000..0d12f8b6 --- /dev/null +++ b/frontend/templates/404.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block title %}404 - Not Found{% endblock %} + +{% block content %} +
+
+

404

+

Oops, we couldn’t find that page!

+

+ It seems DocuNova has misplaced the document you were looking for. Don’t worry – we’ve got your back. +

+ + ← Return Home + +
+
+{% endblock %} diff --git a/frontend/templates/about.html b/frontend/templates/about.html new file mode 100644 index 00000000..11758ded --- /dev/null +++ b/frontend/templates/about.html @@ -0,0 +1,63 @@ +{% extends "base.html" %} +{% block title %}About DocuNova{% endblock %} + +{% block content %} +
+

About DocuNova

+

+ Welcome to DocuNova – your modern, intelligent solution for document processing! + We’ve built DocuNova to completely transform the way you handle your documents – from upload + to extraction, from processing to storage. +

+ + +
+

Our Story

+

+ DocuNova was created with one goal in mind: to simplify and streamline document management + for everyone, whether you’re a small startup or a large enterprise. +

+

+ We harness the power of OpenAI for metadata extraction and text refinement, integrate seamlessly + with Dropbox, Nextcloud, and Paperless NGX for storage and indexing, leverage Azure Document + Intelligence for OCR, and even use Gotenberg for file-to-PDF conversions. +

+
+ + +
+

Key Features

+ +
+ + +
+

Meet the Creator

+

+ DocuNova is passionately developed by + Christian Krakau-Louis. +

+
+ + +
+

Get Involved

+

+ Want to dive into the code, contribute ideas, or simply check out the magic behind DocuNova? + Visit our GitHub repository! +

+ + GitHub Logo + View DocuNova on GitHub + +
+
+{% endblock %} diff --git a/frontend/templates/base.html b/frontend/templates/base.html new file mode 100644 index 00000000..e579112c --- /dev/null +++ b/frontend/templates/base.html @@ -0,0 +1,54 @@ + + + + + + {% block title %}DocuNova{% endblock %} + + + + + {% block head_extra %}{% endblock %} + + + + + + + +
+ {% block content %}{% endblock %} +
+ + + + + + + + + {% block scripts %}{% endblock %} + + diff --git a/frontend/templates/index.html b/frontend/templates/index.html new file mode 100644 index 00000000..0f257b44 --- /dev/null +++ b/frontend/templates/index.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} +{% block title %}Home - DocuNova{% endblock %} + +{% block content %} +
+

Welcome to DocuNova

+

+ Your intelligent solution for processing, managing, and organizing documents effortlessly. +

+ +
+
+

Upload Documents

+

+ Quickly upload and process your files with our user-friendly interface. +

+ + Get Started → + +
+
+

Manage Your Files

+

+ View, organize, and collaborate on your processed files in one central hub. +

+ + View Files → + +
+
+
+{% endblock %} diff --git a/frontend/templates/upload.html b/frontend/templates/upload.html new file mode 100644 index 00000000..5ccbd8f4 --- /dev/null +++ b/frontend/templates/upload.html @@ -0,0 +1,83 @@ +{% extends "base.html" %} +{% block title %}Upload Document{% endblock %} + +{% block content %} +
+

Upload a File

+ +
+

+ Drag & drop a file here, or click to select a file. +

+ +
+ +
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/frontend/upload.html b/frontend/upload.html deleted file mode 100644 index eec9ca34..00000000 --- a/frontend/upload.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - DocuNova - Upload - - - - - - - - - -
-

Upload a File

- -
-

- Drag & drop a file here, or click to select a file. -

- -
- -
-
- - - - - - - -