# UGE / L2 / Intro to relational databases / Python project prototype # Author: Pacien TRAN-GIRARD # Licence: EUPL-1.2 from os import environ from functools import partial from fastapi import Request, HTTPException, status from starlette.middleware.sessions import SessionMiddleware # Use a signed-cookie session manager. # The default SameSite policy offers some protection against CSRF attacks. cookie_key = environ['COOKIE_SECRET_KEY'] SessionManager = partial(SessionMiddleware, secret_key=cookie_key) class FlashMessageQueue: """ Session decorator for managing session flash messages to be displayed to the user from one page to another. This suits confirmation and error messages. Messages are stored in the session cookie, which is limited in size to about 4kb. """ def __init__(self, request: Request): if 'messages' not in request.session: request.session['messages'] = [] self._messages = request.session['messages'] def add(self, class_: str, message: str): self._messages.append((class_, message)) def __iter__(self): return self def __next__(self): if not self._messages: raise StopIteration return self._messages.pop(0) class UserSession: """ Session decorator for managing user login sessions. """ def __init__(self, request: Request): self._session = request.session def is_logged_in(self) -> bool: return 'user_id' in self._session def get_user_id(self) -> int: return self._session['user_id'] def login(self, user_id: int): self._session['user_id'] = user_id def logout(self): self._session.pop('user_id', None) @classmethod def authenticated(cls, request: Request) -> 'UserSession': """ Returns the authenticated user session or raises an HTTP Exception, dropping the request if the user is not logged in. """ session = cls(request) if not session.is_logged_in(): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) return session