added amazon importer and logging smtp
This commit is contained in:
+149
-4
@@ -6,19 +6,34 @@ from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Request, Form, UploadFile
|
||||
from fastapi.responses import HTMLResponse, JSONResponse, Response, StreamingResponse
|
||||
from fastapi.responses import HTMLResponse, JSONResponse, Response
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from sse_starlette.sse import EventSourceResponse
|
||||
|
||||
from app.database import init_db, get_settings, save_settings, get_log_entries
|
||||
from app.database import init_db, get_settings, save_settings, get_log_entries, clear_log_entries, reset_downloaded_invoices
|
||||
from app.mail_processor import process_mailbox, send_test_email, test_imap_connection, create_imap_folder
|
||||
from app.scheduler import start_scheduler, configure_job, get_scheduler_status
|
||||
from app.scanner import process_scanned_pdf, generate_separator_pdf, UPLOAD_DIR
|
||||
from app.smb_processor import process_smb_share, test_smb_connection, create_smb_folder, list_smb_folders
|
||||
from app.amazon_processor import (
|
||||
start_login as amazon_start_login,
|
||||
submit_otp as amazon_submit_otp,
|
||||
get_login_state as amazon_get_login_state,
|
||||
check_session_valid as amazon_check_session,
|
||||
clear_session as amazon_clear_session,
|
||||
process_amazon,
|
||||
start_interactive_login as amazon_start_interactive,
|
||||
get_browser_screenshot as amazon_get_screenshot,
|
||||
send_browser_click as amazon_browser_click,
|
||||
send_browser_type as amazon_browser_type,
|
||||
send_browser_key as amazon_browser_key,
|
||||
close_interactive_login as amazon_close_interactive,
|
||||
is_interactive_login_active as amazon_login_active,
|
||||
)
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
level=getattr(logging, os.environ.get("LOG_LEVEL", "INFO").upper(), logging.INFO),
|
||||
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -44,6 +59,11 @@ templates = Jinja2Templates(directory="app/templates")
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def index(request: Request):
|
||||
return templates.TemplateResponse("scan.html", {"request": request})
|
||||
|
||||
|
||||
@app.get("/settings", response_class=HTMLResponse)
|
||||
async def settings_page(request: Request):
|
||||
settings = await get_settings()
|
||||
logs = await get_log_entries(limit=20)
|
||||
status = get_scheduler_status()
|
||||
@@ -74,8 +94,12 @@ async def _save_form_settings(request: Request) -> dict:
|
||||
"smtp_username": form.get("smtp_username", ""),
|
||||
"smtp_password": form.get("smtp_password") or current.get("smtp_password", ""),
|
||||
"import_email": form.get("import_email", ""),
|
||||
"import_email_eingang": form.get("import_email_eingang", ""),
|
||||
"import_email_ausgang": form.get("import_email_ausgang", ""),
|
||||
"source_folder": form.get("source_folder", "Rechnungen"),
|
||||
"processed_folder": form.get("processed_folder", "Rechnungen/Verarbeitet"),
|
||||
"source_folder_ausgang": form.get("source_folder_ausgang", ""),
|
||||
"processed_folder_ausgang": form.get("processed_folder_ausgang", ""),
|
||||
"interval_minutes": form.get("interval_minutes", "5"),
|
||||
"scheduler_enabled": form.get("scheduler_enabled", "false"),
|
||||
"fetch_since_date": form.get("fetch_since_date", ""),
|
||||
@@ -89,7 +113,11 @@ async def _save_form_settings(request: Request) -> dict:
|
||||
"smb_share": form.get("smb_share", ""),
|
||||
"smb_source_path": form.get("smb_source_path", ""),
|
||||
"smb_processed_path": form.get("smb_processed_path", "Verarbeitet"),
|
||||
"smb_source_path_ausgang": form.get("smb_source_path_ausgang", ""),
|
||||
"smb_processed_path_ausgang": form.get("smb_processed_path_ausgang", ""),
|
||||
"smb_mode": form.get("smb_mode", "forward"),
|
||||
# Debug
|
||||
"debug_save_amazon_pdfs": form.get("debug_save_amazon_pdfs", "false"),
|
||||
}
|
||||
|
||||
await save_settings(data)
|
||||
@@ -194,6 +222,12 @@ async def log_page(request: Request):
|
||||
})
|
||||
|
||||
|
||||
@app.post("/api/clear-log")
|
||||
async def api_clear_log():
|
||||
count = await clear_log_entries()
|
||||
return JSONResponse({"success": True, "count": count})
|
||||
|
||||
|
||||
@app.get("/api/status")
|
||||
async def api_status():
|
||||
return get_scheduler_status()
|
||||
@@ -247,6 +281,7 @@ async def scan_upload_chunk(
|
||||
async def scan_process(request: Request):
|
||||
body = await request.json()
|
||||
upload_id = body.get("upload_id", "")
|
||||
beleg_type = body.get("beleg_type", "eingang")
|
||||
|
||||
try:
|
||||
uuid.UUID(upload_id)
|
||||
@@ -269,7 +304,7 @@ async def scan_process(request: Request):
|
||||
# Process in background task
|
||||
async def _process():
|
||||
try:
|
||||
result = await process_scanned_pdf(str(pdf_path), progress_callback)
|
||||
result = await process_scanned_pdf(str(pdf_path), progress_callback, beleg_type=beleg_type)
|
||||
_scan_progress.setdefault(upload_id, []).append({
|
||||
"stage": "done", "result": result
|
||||
})
|
||||
@@ -325,3 +360,113 @@ async def separator_pdf():
|
||||
media_type="application/pdf",
|
||||
headers={"Content-Disposition": "attachment; filename=Trennseite.pdf"},
|
||||
)
|
||||
|
||||
|
||||
# --- Plattformen (Amazon) ---
|
||||
|
||||
@app.get("/platforms", response_class=HTMLResponse)
|
||||
async def platforms_page(request: Request):
|
||||
settings = await get_settings()
|
||||
status = get_scheduler_status()
|
||||
return templates.TemplateResponse("platforms.html", {
|
||||
"request": request,
|
||||
"settings": settings,
|
||||
"status": status,
|
||||
"message": None,
|
||||
"message_type": None,
|
||||
})
|
||||
|
||||
|
||||
@app.post("/api/amazon-settings")
|
||||
async def api_amazon_settings(request: Request):
|
||||
body = await request.json()
|
||||
current = await get_settings()
|
||||
|
||||
data = {
|
||||
"amazon_enabled": body.get("amazon_enabled", "false"),
|
||||
"amazon_domain": body.get("amazon_domain", "amazon.de"),
|
||||
"amazon_email": body.get("amazon_email", ""),
|
||||
"amazon_password": body.get("amazon_password") or current.get("amazon_password", ""),
|
||||
"amazon_since_date": body.get("amazon_since_date", ""),
|
||||
}
|
||||
await save_settings(data)
|
||||
return JSONResponse({"success": True})
|
||||
|
||||
|
||||
@app.get("/api/amazon-status")
|
||||
async def api_amazon_status():
|
||||
valid = await amazon_check_session()
|
||||
login_active = amazon_login_active()
|
||||
return JSONResponse({"session_valid": valid, "login_active": login_active})
|
||||
|
||||
|
||||
@app.post("/api/amazon-login")
|
||||
async def api_amazon_login():
|
||||
"""Start interactive browser login."""
|
||||
await amazon_start_interactive()
|
||||
return JSONResponse({"success": True})
|
||||
|
||||
|
||||
@app.get("/api/amazon-login-state")
|
||||
async def api_amazon_login_state():
|
||||
return JSONResponse(amazon_get_login_state())
|
||||
|
||||
|
||||
@app.get("/api/amazon-browser-screenshot")
|
||||
async def api_amazon_browser_screenshot():
|
||||
img = await amazon_get_screenshot()
|
||||
if img is None:
|
||||
return JSONResponse({"error": "Kein Browser offen"}, status_code=404)
|
||||
return Response(content=img, media_type="image/png")
|
||||
|
||||
|
||||
@app.post("/api/amazon-browser-click")
|
||||
async def api_amazon_browser_click(request: Request):
|
||||
body = await request.json()
|
||||
await amazon_browser_click(int(body["x"]), int(body["y"]))
|
||||
return JSONResponse({"success": True})
|
||||
|
||||
|
||||
@app.post("/api/amazon-browser-type")
|
||||
async def api_amazon_browser_type(request: Request):
|
||||
body = await request.json()
|
||||
await amazon_browser_type(body["text"])
|
||||
return JSONResponse({"success": True})
|
||||
|
||||
|
||||
@app.post("/api/amazon-browser-key")
|
||||
async def api_amazon_browser_key(request: Request):
|
||||
body = await request.json()
|
||||
await amazon_browser_key(body["key"])
|
||||
return JSONResponse({"success": True})
|
||||
|
||||
|
||||
@app.post("/api/amazon-login-close")
|
||||
async def api_amazon_login_close():
|
||||
await amazon_close_interactive()
|
||||
return JSONResponse({"success": True})
|
||||
|
||||
|
||||
@app.post("/api/amazon-otp")
|
||||
async def api_amazon_otp(request: Request):
|
||||
body = await request.json()
|
||||
ok = await amazon_submit_otp(body.get("code", ""))
|
||||
return JSONResponse({"success": ok})
|
||||
|
||||
|
||||
@app.post("/api/amazon-logout")
|
||||
async def api_amazon_logout():
|
||||
await amazon_clear_session()
|
||||
return JSONResponse({"success": True})
|
||||
|
||||
|
||||
@app.post("/api/amazon-process")
|
||||
async def api_amazon_process():
|
||||
result = await process_amazon()
|
||||
return JSONResponse(result)
|
||||
|
||||
|
||||
@app.post("/api/amazon-reset")
|
||||
async def api_amazon_reset():
|
||||
count = await reset_downloaded_invoices()
|
||||
return JSONResponse({"success": True, "count": count})
|
||||
|
||||
Reference in New Issue
Block a user