from typing import Optional, Union import uuid from datetime import datetime from sqlalchemy.orm import Session from sqlalchemy.exc import SQLAlchemyError # Assuming the models are in a file named `models.py` in the `app.db` directory from app.db import models class UserService: def __init__(self): pass def save_user(self, db: Session, oidc_id: str, email: str, username: str) -> str: """ Saves or updates a user record based on their OIDC ID. If a user with this OIDC ID exists, it returns their existing ID. Otherwise, it creates a new user record. Returns the user's ID. """ try: # Check if a user with this OIDC ID already exists existing_user = db.query(models.User).filter(models.User.oidc_id == oidc_id).first() if existing_user: # Update the user's information if needed existing_user.email = email existing_user.username = username db.commit() return existing_user.id else: # Create a new user record new_user = models.User( id=str(uuid.uuid4()), # Generate a unique ID for the user oidc_id=oidc_id, email=email, username=username, created_at=datetime.utcnow() ) db.add(new_user) db.commit() db.refresh(new_user) return new_user.id except SQLAlchemyError as e: db.rollback() raise def get_user_by_id(self, db: Session, user_id: str) -> Optional[models.User]: """ Retrieves a user record by their unique ID. Returns the User object if found, otherwise None. """ try: # Query the database for a user with the given ID user = db.query(models.User).filter(models.User.id == user_id).first() return user except SQLAlchemyError as e: # Log the error and return None in case of a database issue. print(f"Database error while fetching user by ID: {e}") return None # --- Framework-dependent helper functions --- # These functions are placeholders and would need to be integrated with your # specific web framework (e.g., FastAPI, Flask, Django). def login_required(f): """ A decorator to protect API endpoints and web pages. It ensures a user is logged in and is a registered (non-anonymous) user. If not, it redirects them to the login page. This is a generic implementation. You would replace the logic inside with code specific to your web framework's authentication system. """ async def wrapper(*args, **kwargs): # Placeholder logic: Check for user in the request context # For example, in FastAPI, you might use Depends(get_current_user) # In Flask, you might use session or current_user user_id = kwargs.get("user_id") # Assuming user_id is passed in via a dependency if not user_id: # Depending on the framework, this would return an Unauthorized error or a redirect # For example: raise HTTPException(status_code=401, detail="Unauthorized") pass return await f(*args, **kwargs) return wrapper def get_current_user_id() -> Optional[str]: """ A helper function to get the current user's ID from the session. This is a placeholder and needs to be implemented with your framework's session/authentication management system. """ # Placeholder logic # Example for FastAPI: # from fastapi import Depends, Request # from app.auth import get_current_user # # return get_current_user(request).id # For now, we return None as a generic placeholder return None