diff --git a/.env.example b/.env.example index 2c9e057..f41bfdb 100644 --- a/.env.example +++ b/.env.example @@ -77,10 +77,14 @@ ENABLE_XCTO=1 # Zalecane: 1. Ustaw 0, jeśli używasz zewnętrznych skryptów lub masz problemy z WebSocketami (w CSP: connect-src 'self'). ENABLE_CSP=1 - # ENABLE_PP: # Ustawia nagłówek Permissions-Policy, który ogranicza wybrane funkcje przeglądarki (np. Topics API od Google). # Domyślnie wyłączone. Włączenie ustawi: Permissions-Policy: browsing-topics=() # Zalecane: 1 — jeśli chcesz zwiększyć prywatność użytkowników i zablokować Topics API. # Ustaw 0, jeśli chcesz całkowicie pominąć ten nagłówek. ENABLE_PP=0 + +# DEBUG_MODE: +# Czy uruchomić aplikację w trybie debugowania (z konsolą błędów i autoreloaderem) +# Domyślnie: 1 +DEBUG_MODE=1 \ No newline at end of file diff --git a/app.py b/app.py index 51dada5..8fc9698 100644 --- a/app.py +++ b/app.py @@ -8,10 +8,11 @@ import platform import psutil import hashlib import re +import traceback from pillow_heif import register_heif_opener - from datetime import datetime, timedelta, UTC, timezone +from urllib.parse import urlparse, urlunparse from flask import ( Flask, @@ -52,20 +53,12 @@ from functools import wraps from flask_talisman import Talisman # OCR -from collections import Counter import pytesseract +from collections import Counter from pytesseract import Output +import logging -if os.environ.get("FLASK_RUN_FROM_CLI") == "true": - print(""" - NIE URUCHAMIAJ aplikacji przez `flask run`! - - Socket.IO wymaga uruchamiania przez `python app.py`, bo `flask run` - nie obsługuje WebSocketów poprawnie (działa tylko z Werkzeugem). - - Użyj: `python app.py` - """) - sys.exit(1) +logging.getLogger("werkzeug").setLevel(logging.INFO) app = Flask(__name__) app.config.from_object(Config) @@ -74,17 +67,15 @@ app.config.from_object(Config) csp_policy = None if app.config.get("ENABLE_CSP", True): csp_policy = { - 'default-src': "'self'", - 'script-src': "'self'", # wciąż bez inline JS - 'style-src': "'self' 'unsafe-inline'", # dopuszczamy style w HTML-u - 'img-src': "'self' data:", # pozwalamy na data:image (np. SVG) - 'connect-src': "'self'", # WebSockety - 'script-src': "'self' 'unsafe-inline'" + "default-src": "'self'", + "script-src": "'self'", # wciąż bez inline JS + "style-src": "'self' 'unsafe-inline'", # dopuszczamy style w HTML-u + "img-src": "'self' data:", # pozwalamy na data:image (np. SVG) + "connect-src": "'self'", # WebSockety + "script-src": "'self' 'unsafe-inline'", } -permissions_policy = { - "browsing-topics": "()" -} if app.config["ENABLE_PP"] else None +permissions_policy = {"browsing-topics": "()"} if app.config["ENABLE_PP"] else None talisman = Talisman( app, @@ -94,8 +85,7 @@ talisman = Talisman( permissions_policy=permissions_policy, content_security_policy=csp_policy, x_content_type_options=app.config.get("ENABLE_XCTO", True), - strict_transport_security_include_subdomains=False - + strict_transport_security_include_subdomains=False, ) register_heif_opener() # pillow_heif dla HEIC @@ -115,6 +105,7 @@ SESSION_TIMEOUT_MINUTES = int(app.config.get("SESSION_TIMEOUT_MINUTES", 10080)) app.config["COMPRESS_ALGORITHM"] = ["zstd", "br", "gzip", "deflate"] app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=SESSION_TIMEOUT_MINUTES) app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1) +DEBUG_MODE = app.config.get("DEBUG_MODE", False) os.makedirs(UPLOAD_FOLDER, exist_ok=True) @@ -437,9 +428,6 @@ def preprocess_image_for_tesseract(image): def extract_total_tesseract(image): - import pytesseract - from pytesseract import Output - import re text = pytesseract.image_to_string(image, lang="pol", config="--psm 4") lines = text.splitlines() @@ -627,8 +615,6 @@ def require_system_password(): if request.path == "/": return redirect(url_for("system_auth")) - from urllib.parse import urlparse, urlunparse - parsed = urlparse(request.url) fixed_url = urlunparse(parsed._replace(netloc=request.host)) return redirect(url_for("system_auth", next=fixed_url)) @@ -1416,8 +1402,6 @@ def analyze_receipts_for_list(list_id): value, lines = extract_total_tesseract(image) except Exception as e: - import traceback - print(f"OCR error for {receipt.filename}:\n{traceback.format_exc()}") value = 0.0 lines = [] @@ -2609,11 +2593,15 @@ def create_db(): extra_cols = actual_columns - expected_columns if missing_cols: - print(f"Brakuje kolumn w tabeli '{table}': {', '.join(sorted(missing_cols))}") + print( + f"Brakuje kolumn w tabeli '{table}': {', '.join(sorted(missing_cols))}" + ) critical_error = True if extra_cols: - print(f"ℹDodatkowe kolumny w tabeli '{table}': {', '.join(sorted(extra_cols))}") + print( + f"ℹDodatkowe kolumny w tabeli '{table}': {', '.join(sorted(extra_cols))}" + ) if missing_tables or critical_error: print("Struktura bazy jest niekompletna lub niezgodna. Przerwano.") @@ -2627,4 +2615,4 @@ def create_db(): if __name__ == "__main__": - socketio.run(app, host="0.0.0.0", port=8000, debug=True) + socketio.run(app, host="0.0.0.0", port=8000, debug=DEBUG_MODE) diff --git a/config.py b/config.py index 9670bf2..a4408bc 100644 --- a/config.py +++ b/config.py @@ -36,3 +36,5 @@ class Config: ENABLE_XCTO = os.environ.get("ENABLE_XCTO", "0") == "1" ENABLE_CSP = os.environ.get("ENABLE_CSP", "0") == "1" ENABLE_PP = os.environ.get("ENABLE_PP", "0") == "1" + + DEBUG_MODE = os.environ.get("DEBUG_MODE", "1") == "1" \ No newline at end of file