Log generic webhook for now

This commit is contained in:
Jonas Linter
2025-10-14 14:43:59 +02:00
parent 8f2565b5a9
commit 3714226b08

View File

@@ -33,7 +33,6 @@ from .db import Base, get_database_url
from .db import Customer as DBCustomer from .db import Customer as DBCustomer
from .db import Reservation as DBReservation from .db import Reservation as DBReservation
from .logging_config import get_logger, setup_logging from .logging_config import get_logger, setup_logging
from .reservation_service import ReservationService
from .rate_limit import ( from .rate_limit import (
BURST_RATE_LIMIT, BURST_RATE_LIMIT,
DEFAULT_RATE_LIMIT, DEFAULT_RATE_LIMIT,
@@ -42,6 +41,7 @@ from .rate_limit import (
limiter, limiter,
webhook_limiter, webhook_limiter,
) )
from .reservation_service import ReservationService
# Configure logging - will be reconfigured during lifespan with actual config # Configure logging - will be reconfigured during lifespan with actual config
_LOGGER = get_logger(__name__) _LOGGER = get_logger(__name__)
@@ -137,7 +137,7 @@ async def push_listener(customer: DBCustomer, reservation: DBReservation, hotel)
_LOGGER.info( _LOGGER.info(
"Created directory owner: uid:%s, gid:%s", "Created directory owner: uid:%s, gid:%s",
stat_info.st_uid, stat_info.st_uid,
stat_info.st_gid stat_info.st_gid,
) )
_LOGGER.info("Directory mode: %s", oct(stat_info.st_mode)[-3:]) _LOGGER.info("Directory mode: %s", oct(stat_info.st_mode)[-3:])
log_filename = f"{logs_dir}/alpinebits_push_{hotel_id}_{reservation.unique_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xml" log_filename = f"{logs_dir}/alpinebits_push_{hotel_id}_{reservation.unique_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xml"
@@ -159,20 +159,20 @@ async def push_listener(customer: DBCustomer, reservation: DBReservation, hotel)
) )
_LOGGER.info( _LOGGER.info(
"Push event fired to %s for hotel %s, status: %s", "Push event fired to %s for hotel %s, status: %s",
push_endpoint['url'], push_endpoint["url"],
hotel['hotel_id'], hotel["hotel_id"],
resp.status_code resp.status_code,
) )
if resp.status_code not in [200, 201, 202]: if resp.status_code not in [200, 201, 202]:
_LOGGER.warning( _LOGGER.warning(
"Push endpoint returned non-success status %s: %s", "Push endpoint returned non-success status %s: %s",
resp.status_code, resp.status_code,
resp.text resp.text,
) )
except Exception as e: except Exception as e:
_LOGGER.exception("Push event failed for hotel %s: %s", hotel['hotel_id'], e) _LOGGER.exception("Push event failed for hotel %s: %s", hotel["hotel_id"], e)
# Optionally implement retry logic here@asynccontextmanager # Optionally implement retry logic here@asynccontextmanager
@@ -528,9 +528,7 @@ async def process_generic_webhook_submission(
hotel_name = hotel_data.get("hotelname") hotel_name = hotel_data.get("hotelname")
if not hotel_code: if not hotel_code:
_LOGGER.warning( _LOGGER.warning("No hotel_code provided in webhook data, using default")
"No hotel_code provided in webhook data, using default"
)
hotel_code = request.app.state.config.get("default_hotel_code", "123") hotel_code = request.app.state.config.get("default_hotel_code", "123")
if not hotel_name: if not hotel_name:
@@ -553,8 +551,7 @@ async def process_generic_webhook_submission(
if not start_date_str or not end_date_str: if not start_date_str or not end_date_str:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400, detail="Missing required dates (anreise/abreise)"
detail="Missing required dates (anreise/abreise)"
) )
try: try:
@@ -568,9 +565,7 @@ async def process_generic_webhook_submission(
end_date_str, end_date_str,
e, e,
) )
raise HTTPException( raise HTTPException(status_code=400, detail=f"Invalid date format: {e}") from e
status_code=400, detail=f"Invalid date format: {e}"
) from e
# Extract room/guest info # Extract room/guest info
num_adults = int(form_data.get("erwachsene", 2)) num_adults = int(form_data.get("erwachsene", 2))
@@ -586,9 +581,7 @@ async def process_generic_webhook_submission(
try: try:
children_ages.append(int(age_str)) children_ages.append(int(age_str))
except ValueError: except ValueError:
_LOGGER.warning( _LOGGER.warning("Invalid age value for child %d: %s", i, age_str)
"Invalid age value for child %d: %s", i, age_str
)
# Extract tracking information # Extract tracking information
utm_source = tracking_data.get("utm_source") utm_source = tracking_data.get("utm_source")
@@ -608,9 +601,7 @@ async def process_generic_webhook_submission(
submission_time = datetime.fromisoformat(submission_time[:-1]) submission_time = datetime.fromisoformat(submission_time[:-1])
elif "+" in submission_time: elif "+" in submission_time:
# Remove timezone info (e.g., +02:00) # Remove timezone info (e.g., +02:00)
submission_time = datetime.fromisoformat( submission_time = datetime.fromisoformat(submission_time.split("+")[0])
submission_time.split("+")[0]
)
else: else:
submission_time = datetime.fromisoformat(submission_time) submission_time = datetime.fromisoformat(submission_time)
except Exception as e: except Exception as e:
@@ -673,9 +664,7 @@ async def process_generic_webhook_submission(
reservation = ReservationData(**reservation_kwargs) reservation = ReservationData(**reservation_kwargs)
if reservation.md5_unique_id is None: if reservation.md5_unique_id is None:
raise HTTPException( raise HTTPException(status_code=400, detail="Failed to generate md5_unique_id")
status_code=400, detail="Failed to generate md5_unique_id"
)
# Use ReservationService to create reservation # Use ReservationService to create reservation
reservation_service = ReservationService(db) reservation_service = ReservationService(db)
@@ -693,9 +682,7 @@ async def process_generic_webhook_submission(
await dispatcher.dispatch_for_hotel( await dispatcher.dispatch_for_hotel(
"form_processed", hotel_code, db_customer, db_reservation "form_processed", hotel_code, db_customer, db_reservation
) )
_LOGGER.info( _LOGGER.info("Dispatched form_processed event for hotel %s", hotel_code)
"Dispatched form_processed event for hotel %s", hotel_code
)
else: else:
_LOGGER.warning( _LOGGER.warning(
"No hotel_code in reservation, skipping push notifications" "No hotel_code in reservation, skipping push notifications"
@@ -704,13 +691,10 @@ async def process_generic_webhook_submission(
# Create task and store reference to prevent garbage collection # Create task and store reference to prevent garbage collection
task = asyncio.create_task(push_event()) task = asyncio.create_task(push_event())
# Add done callback to log any exceptions # Add done callback to log any exceptions
task.add_done_callback( task.add_done_callback(lambda t: t.exception() if not t.cancelled() else None)
lambda t: t.exception() if not t.cancelled() else None
)
_LOGGER.info( _LOGGER.info(
"Successfully processed generic webhook: customer_id=%s, " "Successfully processed generic webhook: customer_id=%s, reservation_id=%s",
"reservation_id=%s",
db_customer.id, db_customer.id,
db_reservation.id, db_reservation.id,
) )
@@ -791,11 +775,13 @@ async def handle_wix_form(
logs_dir = Path("logs/errors") logs_dir = Path("logs/errors")
await asyncio.to_thread(logs_dir.mkdir, parents=True, mode=0o755, exist_ok=True) await asyncio.to_thread(logs_dir.mkdir, parents=True, mode=0o755, exist_ok=True)
log_filename = logs_dir / f"wix_error_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" log_filename = (
logs_dir / f"wix_error_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
)
await asyncio.to_thread( await asyncio.to_thread(
log_filename.write_text, log_filename.write_text,
json.dumps(log_entry, indent=2, default=str, ensure_ascii=False), json.dumps(log_entry, indent=2, default=str, ensure_ascii=False),
encoding="utf-8" encoding="utf-8",
) )
_LOGGER.error("Error data logged to: %s", log_filename) _LOGGER.error("Error data logged to: %s", log_filename)
@@ -832,11 +818,13 @@ async def handle_wix_form_test(
logs_dir = Path("logs/errors") logs_dir = Path("logs/errors")
await asyncio.to_thread(logs_dir.mkdir, parents=True, mode=0o755, exist_ok=True) await asyncio.to_thread(logs_dir.mkdir, parents=True, mode=0o755, exist_ok=True)
log_filename = logs_dir / f"wix_test_error_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" log_filename = (
logs_dir / f"wix_test_error_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
)
await asyncio.to_thread( await asyncio.to_thread(
log_filename.write_text, log_filename.write_text,
json.dumps(log_entry, indent=2, default=str, ensure_ascii=False), json.dumps(log_entry, indent=2, default=str, ensure_ascii=False),
encoding="utf-8" encoding="utf-8",
) )
_LOGGER.error("Error data logged to: %s", log_filename) _LOGGER.error("Error data logged to: %s", log_filename)
@@ -866,9 +854,7 @@ async def handle_generic_webhook(
body = await request.body() body = await request.body()
if not body: if not body:
raise HTTPException( raise HTTPException(status_code=400, detail="ERROR: No content provided")
status_code=400, detail="ERROR: No content provided"
)
# Check if content is gzip compressed # Check if content is gzip compressed
content_encoding = request.headers.get("content-encoding", "").lower() content_encoding = request.headers.get("content-encoding", "").lower()
@@ -894,6 +880,22 @@ async def handle_generic_webhook(
detail=f"ERROR: Invalid JSON content: {e}", detail=f"ERROR: Invalid JSON content: {e}",
) from e ) from e
if True:
# log to file for now
logs_dir = Path("logs/generic_webhooks")
await asyncio.to_thread(
logs_dir.mkdir, parents=True, mode=0o755, exist_ok=True
)
log_filename = (
logs_dir
/ f"generic_webhook_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
)
await asyncio.to_thread(
log_filename.write_text,
json.dumps(data, indent=2, default=str, ensure_ascii=False),
encoding="utf-8",
)
# Process the webhook data and save to database # Process the webhook data and save to database
await process_generic_webhook_submission(request, data, db_session) await process_generic_webhook_submission(request, data, db_session)