From a94ec11c80560755571c5cd3fe7eaaeb0ba6dc17 Mon Sep 17 00:00:00 2001 From: Stefano Date: Mon, 9 Feb 2026 12:31:06 +0100 Subject: [PATCH] ad TIMEZONE and more --- .env.prod | 13 +++++---- app/config.py | 2 ++ app/routes/auth.py | 10 +++++-- fix_db_index.py | 61 --------------------------------------- services/notifications.py | 50 +++++++++++++++++++++++++++----- 5 files changed, 60 insertions(+), 76 deletions(-) delete mode 100644 fix_db_index.py diff --git a/.env.prod b/.env.prod index ce78d41..e2c0c4f 100644 --- a/.env.prod +++ b/.env.prod @@ -13,6 +13,8 @@ SECRET_KEY=766299d3235f79a2a9a35aafbc90bec7102f250dfe4aba83500b98e568289b7a # Usa 0.0.0.0 per permettere connessioni dall'esterno del container (essenziale per Docker/Traefik) HOST=0.0.0.0 PORT=8000 +# Timezone per l'applicazione (cronjobs, notifiche, ecc.) +TIMEZONE=Europe/Rome # Database (SQLite path) # Percorso assoluto nel container @@ -25,6 +27,7 @@ DATABASE_PATH=/app/data/parking.db # JWT token expiration (minutes, default 24 hours) ACCESS_TOKEN_EXPIRE_MINUTES=1440 +COOKIE_SECURE=true # Logging level (DEBUG, INFO, WARNING, ERROR) LOG_LEVEL=INFO @@ -64,14 +67,14 @@ AUTHELIA_LOGOUT_URL=https://auth.rocketscale.it/logout # Email Notifications # ============================================================================= # Set to true to enable email sending -SMTP_ENABLED=false +SMTP_ENABLED=true # SMTP server configuration -SMTP_HOST=localhost +SMTP_HOST="smtp.email.eu-milan-1.oci.oraclecloud.com" SMTP_PORT=587 -SMTP_USER= -SMTP_PASSWORD= -SMTP_FROM=noreply@parking.local +SMTP_USER="ocid1.user.oc1..aaaaaaaa6bollovnlx4vxoq2eh7pzgxxhludqitgxsp6fevpllmqynug2uiq@ocid1.tenancy.oc1..aaaaaaaa6veuezxddkzbxmxnjp5thywdjz42z5qfrd6mmosmqehvebrewola.hj.com" +SMTP_PASSWORD="3)J2E9_Np:}#kozD2Wed" +SMTP_FROM="noreply@rocketscale.it" SMTP_USE_TLS=true # When SMTP is disabled, emails are logged to this file diff --git a/app/config.py b/app/config.py index 0fba526..f4ceb78 100644 --- a/app/config.py +++ b/app/config.py @@ -46,10 +46,12 @@ if SECRET_KEY == "change-me-in-production": ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "1440")) # 24 hours +COOKIE_SECURE = os.getenv("COOKIE_SECURE", "false").lower() == "true" # Server HOST = os.getenv("HOST", "0.0.0.0") PORT = int(os.getenv("PORT", "8000")) +TIMEZONE = os.getenv("TIMEZONE", "UTC") # CORS ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "http://localhost:8000,http://127.0.0.1:8000,http://lvh.me").split(",") diff --git a/app/routes/auth.py b/app/routes/auth.py index d274752..3aef1f6 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -104,7 +104,8 @@ def login(request: Request, data: LoginRequest, response: Response, db: Session value=token, httponly=True, max_age=config.ACCESS_TOKEN_EXPIRE_MINUTES * 60, - samesite="lax" + samesite="lax", + secure=config.COOKIE_SECURE ) config.logger.info(f"User logged in: {data.email}") @@ -114,7 +115,12 @@ def login(request: Request, data: LoginRequest, response: Response, db: Session @router.post("/logout") def logout(response: Response): """Logout and clear session""" - response.delete_cookie("session_token") + response.delete_cookie( + key="session_token", + httponly=True, + samesite="lax", + secure=config.COOKIE_SECURE + ) return {"message": "Logged out"} diff --git a/fix_db_index.py b/fix_db_index.py deleted file mode 100644 index 7502c5a..0000000 --- a/fix_db_index.py +++ /dev/null @@ -1,61 +0,0 @@ -import sqlite3 -import os -import time - -# Function to find the db file -def find_db(): - candidates = [ - 'data/parking.db', - '/home/ssalemi/org-parking/data/parking.db', - './data/parking.db' - ] - for path in candidates: - if os.path.exists(path): - return path - return None - -db_path = find_db() - -if not db_path: - print("Error: Could not find data/parking.db. Make sure you are in the project root.") - exit(1) - -print(f"Target Database: {db_path}") -print("Attempting to fix 'parking_exclusions' index...") - -try: - conn = sqlite3.connect(db_path) - cursor = conn.cursor() - - # Turn off foreign keys temporarily to avoid issues during schema modification if needed - cursor.execute("PRAGMA foreign_keys=OFF") - - # 1. Drop the existing unique index - print("Dropping index idx_exclusion_office_user...") - try: - cursor.execute("DROP INDEX IF EXISTS idx_exclusion_office_user") - print("Index dropped successfully.") - except Exception as e: - print(f"Warning during drop: {e}") - - # 2. Recreate it as non-unique - print("Creating non-unique index idx_exclusion_office_user...") - try: - cursor.execute("CREATE INDEX idx_exclusion_office_user ON parking_exclusions (office_id, user_id)") - print("Index created successfully.") - except Exception as e: - print(f"Error creating index: {e}") - exit(1) - - conn.commit() - conn.close() - print("\nSUCCESS: Database updated. You can now define multiple exclusions per user.") - -except sqlite3.OperationalError as e: - if "locked" in str(e): - print("\nERROR: Database is LOCKED.") - print("Please STOP the running application (Docker) and try again.") - else: - print(f"\nError: {e}") -except Exception as e: - print(f"\nUnexpected Error: {e}") diff --git a/services/notifications.py b/services/notifications.py index 164d11e..f24c46b 100644 --- a/services/notifications.py +++ b/services/notifications.py @@ -291,11 +291,15 @@ def run_scheduled_notifications(db: "Session"): Schedule: - Thursday at 12:00: Presence reminder for next week - Friday at 12:00: Weekly parking summary - - Daily at user's preferred time: Daily parking reminder (Mon-Fri) + - Daily at user's preferred time: Daily parking reminder (Only on open days) """ - from database.models import User + from database.models import User, OfficeWeeklyClosingDay, OfficeClosingDay + from zoneinfo import ZoneInfo - now = datetime.now() + # Use configured timezone + tz = ZoneInfo(config.TIMEZONE) + now = datetime.now(tz) + current_hour = now.hour current_minute = now.minute current_weekday = now.weekday() # 0=Monday, 6=Sunday @@ -309,9 +313,39 @@ def run_scheduled_notifications(db: "Session"): next_week = get_next_week_dates(today_date) send_presence_reminder(user, next_week, db) - # Daily parking reminder at user's preferred time (working days only) - if current_weekday < 5: # Monday to Friday - user_hour = user.notify_daily_parking_hour or 8 - user_minute = user.notify_daily_parking_minute or 0 - if current_hour == user_hour and abs(current_minute - user_minute) < 5: + # Daily parking reminder at user's preferred time + user_hour = user.notify_daily_parking_hour or 8 + user_minute = user.notify_daily_parking_minute or 0 + + # Check if it's the right time for this user + if current_hour == user_hour and abs(current_minute - user_minute) < 5: + # Check if Office is OPEN today + is_office_open = True + + if user.office: + # Check weekly closing days (e.g. Sat/Sun) + # Note: WeekDay enum matches python weekday (0=Mon) + weekly_closed = db.query(OfficeWeeklyClosingDay).filter( + OfficeWeeklyClosingDay.office_id == user.office_id, + OfficeWeeklyClosingDay.weekday == current_weekday + ).first() + + if weekly_closed: + is_office_open = False + + # Check specific closing days (Holidays) + if is_office_open: + specific_closed = db.query(OfficeClosingDay).filter( + OfficeClosingDay.office_id == user.office_id, + OfficeClosingDay.date == today_date + ).first() + + if specific_closed: + is_office_open = False + else: + # Fallback if no office assigned: default to Mon-Fri open + if current_weekday >= 5: + is_office_open = False + + if is_office_open: send_daily_parking_reminder(user, now, db)