From 3414173fad4a6dde983b70d062c1468e3e9c6bec Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:44:00 +0200 Subject: [PATCH 01/42] Python 3.11 to 3.12 --- .gitignore | 1 - .python-version | 1 + README.md | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 .python-version diff --git a/.gitignore b/.gitignore index 12a8f754f3..bdf05aeda4 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ firebase.json # Virtual environment .venv -.python-version # Logs logs/ diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000..25ce095ac1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12.11 \ No newline at end of file diff --git a/README.md b/README.md index 913222d0ad..4e09d4e367 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Hyperion is the API of an open-source project launched by ÉCLAIR, the computer The structure of this project is modular. Hyperion has a core that performs vital functions (authentication, database migration, authorization, etc). The other functions of Hyperion are realized in what we call modules. You can contribute to the project by adding modules if you wish. -## Creating a virtual environment for Python 3.11.x +## Creating a virtual environment for Python 3.12 ### Windows @@ -17,7 +17,7 @@ Create the virtual environment > You need to be in Hyperion main folder ```bash -py -3.11 -m venv .venv +py -3.12 -m venv .venv ``` Activate it @@ -45,7 +45,7 @@ eval "$(pyenv virtualenv-init -)" Create the virtual environment ```bash -pyenv virtualenv 3.11.0 hyperion +pyenv virtualenv 3.12.0 hyperion ``` Activate it From 945a7ce3ce5b1db23eabadb7d7e9b0a71a4fd3c6 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:45:34 +0200 Subject: [PATCH 02/42] About requirements --- README.md | 42 +++++++++++++++++++++++++++++++++-------- requirements-common.txt | 1 - 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4e09d4e367..27cf9e9f4c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,18 @@ Create the virtual environment py -3.12 -m venv .venv ``` +If you get an error saying roughly: + +``` +because the execution of scripts is disabled on this system. Please see "get-help about_signing" for more details. +``` + +Then in a Powershell, run this to allow scripts executions for your user: + +```ps1 +Set-ExecutionPolicy Unrestricted -Scope CurrentUser +``` + Activate it ```bash @@ -56,21 +68,35 @@ pyenv activate hyperion ## Install dependencies -### Development requirements +### About Jellyfish and Rust + +If you don't have Rust installed or don't want to install it, decrase the version of `jellyfish` to `0.10.0` in the `requirements-common.txt` file: + +``` +jellyfish==0.10.0 # String Matching +``` + +### About Weasyprint and Pango + +Follow the installation steps at https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation. + +For Windows, the best way is through MSYS2, Mac users can simply install using Homebrew. + +### Install dependencies (for real) + +Install the dependencies you'll need using `pip` (the common requirements are included in the development requirements): ```bash pip install -r requirements-dev.txt ``` -> If you need to remove all modules from your virtual environnement, you may use the following command with caution -> -> ```bash -> pip freeze | xargs pip uninstall -y -> ``` +If you changed the version of Jellyfish, don't forget to set it back: -## Linting and formating +``` +jellyfish==1.0.4 # String Matching +``` -To lint and format, we currently use `Ruff`. We also use `Mypy` for the type checking. +> If you need to remove all modules from your virtual environnement, delete your `.venv` folder. Before each PR or git push you will need to run `ruff check --fix && ruff format` in order to format/lint your code and `mypy .` in order to verify that there is no type mismatch. diff --git a/requirements-common.txt b/requirements-common.txt index 16550e43db..538a870a9e 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -22,7 +22,6 @@ pydantic==2.7.4 pyjwt[crypto]==2.8.0 # generate and verify the JWT tokens, imported as `jwt` PyMuPDF==1.24.9 # PDF processing, imported as `fitz` pypdf==4.3.1 -python-dotenv==1.0.1 # load environment variables from .env file python-multipart==0.0.18 # a form data parser, as oauth flow requires form-data parameters redis==5.0.8 requests==2.32.4 From 39c61d01c5ef02cc837aa84330696b0170fcdff7 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:49:04 +0200 Subject: [PATCH 03/42] About the db --- .env.template | 4 +- .gitignore | 8 +-- README.md | 107 ++++++++++++++++++++++++++++++--------- app/core/utils/config.py | 1 - 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/.env.template b/.env.template index 0f1d31bceb..5bd67a6f44 100644 --- a/.env.template +++ b/.env.template @@ -3,11 +3,13 @@ ############################ # Should be set to the name of the postgres container -POSTGRES_HOST="hyperion-db" POSTGRES_USER="" POSTGRES_PASSWORD="" +POSTGRES_HOST="" POSTGRES_DB="hyperion" POSTGRES_TZ="Etc/UTC" +# The database can be accessed through the command line with +# psql -U $POSTGRES_USER -d $POSTGRES_DB ######################## # Redis configuration # diff --git a/.gitignore b/.gitignore index bdf05aeda4..c90c8b7ecc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,11 @@ __pycache__ .pytest_cache .ruff_cache -# Databases and data -sql_app.db -test.db +# Databases +*.db +hyperion-db + +# Persistent data as files data/ # Dotenv file diff --git a/README.md b/README.md index 27cf9e9f4c..0830376be8 100644 --- a/README.md +++ b/README.md @@ -98,44 +98,101 @@ jellyfish==1.0.4 # String Matching > If you need to remove all modules from your virtual environnement, delete your `.venv` folder. -Before each PR or git push you will need to run `ruff check --fix && ruff format` in order to format/lint your code and `mypy .` in order to verify that there is no type mismatch. +## Install and configure a database -## Complete the dotenv (`.env`) +Choose either SQLite or PostgreSQL. -> Hyperion settings are documented in [app/core/config.py](./app/core/config.py). -> Check this file to know what can and should be set using the dotenv. +### SQLite -`SQLITE_DB` is None by default. If you want to use SQLite (if you don't use docker or don't have a postgres running), set it with the name of the db file (`app.db` for example). +#### Advantages -`ACCESS_TOKEN_SECRET_KEY` should be a strong random key, which will be used to sign JWT tokens +It is a binary. +This means: -`RSA_PRIVATE_PEM_STRING` will be used to sign JWS tokens +- SQLite is lightweight +- It is directly understood by your machine, no special configuration is needed. + +#### Disadvantages + +Being so light, it does not support some features nowadays common for relational databases: + +- Drop your database on every migration: Alembic uses features incompatible with SQLite + +#### Installation and configuration + +There is nothing to do, it works out of the box. + +### PostgreSQL + +#### Advantages + +Its advantages are many: + +- Very powerful database: it supports all the features you'll ever need. +- Used in production for Hyperion. +- Widely used in production in enterprise-grade services: useful competence on your résumé. +- Supports migrations with Alembic. +- A powerful CLI tool. + +#### Disadvantages + +None (not so heavy, configuration not so hard). + +#### Configuration + +##### Without Docker: native binaries + +1. Download the installer: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads +2. Launch it and trust the wizard + - Keep the default folders and ports, install it all, etc... + - ...but put a concise password you'd remember, choose your language + - Don't use the "Stack Builder" (not needed) +3. On Windows: in your path, add `C:\Program Files\PostgreSQL\17\bin` and `C:\Program Files\PostgreSQL\17\lib` (if you installed Postgres 17 in that location) +4. Create a database named `hyperion` + +```sh +psql -U postgres -c "CREATE DATABASE hyperion;" +``` + +Now your Hyperion database can be explored by hand (as the `postgres` user, using your password you chose) with: ```bash -# Generate a 2048 bits long PEM certificate and replace newlines by `\n` -openssl req -newkey rsa:2048 -nodes -x509 -days 365 | sed 's/$/\\n/g' | tr -d '\n' -# If you only want to generate a PEM certificate and save it in a file, th following command may be used -# openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem +psql -U postgres -d hyperion ``` -`REDIS` may be left blank to disable Redis during development -Numerical values are example, change it to your needs +then running SQL or Postgres commands in this shell, or -```python -REDIS_HOST = "localhost" #May be left at "" during dev if you don't have a redis server running -REDIS_PORT = 6379 -#REDIS_PASSWORD = "pass" Should be commented during development to work with docker-compose-dev, and set in production -REDIS_LIMIT = 1000 -REDIS_WINDOW = 60 +```bash +psql -U postgres -d hyperion -c "select firstname from core_user;" ``` -`POSTGRES`: This section will be ignored if `SQLITE_DB` is set to True. +##### With Docker + +> [!WARNING] +> Work in progress -```python -POSTGRES_HOST = "localhost" -POSTGRES_USER = "hyperion" -POSTGRES_PASSWORD = "pass" -POSTGRES_DB = "hyperion" +``` +services: + hyperion-db: + image: postgres:15.1 + container_name: hyperion-db + restart: unless-stopped + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ] + interval: 5s + timeout: 5s + retries: 5 + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_HOST: ${POSTGRES_HOST} + POSTGRES_DB: ${POSTGRES_DB} + PGTZ: ${POSTGRES_TZ} + ports: + - 5432:5432 + volumes: + - ./hyperion-db:/var/lib/postgresql/data +``` ``` ## Launch the API diff --git a/app/core/utils/config.py b/app/core/utils/config.py index 4be453f6ae..e66fdcf1f6 100644 --- a/app/core/utils/config.py +++ b/app/core/utils/config.py @@ -175,7 +175,6 @@ def settings_customise_sources( POSTGRES_USER: str = "" POSTGRES_PASSWORD: str = "" POSTGRES_DB: str = "" - POSTGRES_TZ: str = "" DATABASE_DEBUG: bool = False # If True, the database will log all queries USE_FACTORIES: bool = ( False # If True, the database will be populated with fake data From 94b25fd5ea51f80eec8e343722d6986461106b5d Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:49:46 +0200 Subject: [PATCH 04/42] While I'm touching the .gitignore --- .gitignore | 12 ++++-------- app/core/auth/endpoints_auth.py | 3 --- app/core/users/endpoints_users.py | 2 -- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index c90c8b7ecc..51feb75a56 100644 --- a/.gitignore +++ b/.gitignore @@ -11,15 +11,12 @@ hyperion-db # Persistent data as files data/ -# Dotenv file +# Configuration and secrets files .env config.yaml - - -# Firebase secrets firebase.json -# macOS +# MacOS .DS_Store # Virtual environment @@ -31,10 +28,9 @@ logs/ # Pytest-cov .coverage -# Jinja templates test output +# Jinja output templates and test output tests/jinja_test_outputs/ +node_modules # Local testing scripts/ - -node_modules \ No newline at end of file diff --git a/app/core/auth/endpoints_auth.py b/app/core/auth/endpoints_auth.py index 96f236c189..6dcdfb97d7 100644 --- a/app/core/auth/endpoints_auth.py +++ b/app/core/auth/endpoints_auth.py @@ -17,7 +17,6 @@ ) from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.security import OAuth2PasswordRequestForm -from fastapi.templating import Jinja2Templates from sqlalchemy.ext.asyncio import AsyncSession from app.core.auth import cruds_auth, models_auth, schemas_auth @@ -53,8 +52,6 @@ factory=None, ) -templates = Jinja2Templates(directory="assets/templates") - # We could maybe use hyperion.security hyperion_access_logger = logging.getLogger("hyperion.access") hyperion_security_logger = logging.getLogger("hyperion.security") diff --git a/app/core/users/endpoints_users.py b/app/core/users/endpoints_users.py index a3f7cdb39b..a2cb63bc6c 100644 --- a/app/core/users/endpoints_users.py +++ b/app/core/users/endpoints_users.py @@ -16,7 +16,6 @@ UploadFile, ) from fastapi.responses import FileResponse, RedirectResponse -from fastapi.templating import Jinja2Templates from sqlalchemy.ext.asyncio import AsyncSession from app.core.auth import cruds_auth @@ -65,7 +64,6 @@ hyperion_error_logger = logging.getLogger("hyperion.error") hyperion_security_logger = logging.getLogger("hyperion.security") hyperion_s3_logger = logging.getLogger("hyperion.s3") -templates = Jinja2Templates(directory="assets/templates") S3_USER_SUBFOLDER = "users" From fd8f8ac8b6e76a0718ccccec4ad733feefa6b879 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:50:53 +0200 Subject: [PATCH 05/42] Unrelated: about pyproject.toml --- .vscode/extensions.json | 13 +++++++------ app/core/utils/config.py | 2 +- pyproject.toml | 10 ++++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 95d418c7b2..57739f63ba 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,8 @@ { - "recommendations": [ - "ms-python.python", - "ms-python.mypy-type-checker", - "charliermarsh.ruff", - ] -} \ No newline at end of file + "recommendations": [ + "ms-python.python", + "ms-python.mypy-type-checker", + "charliermarsh.ruff", + "tamasfe.even-better-toml" + ] +} diff --git a/app/core/utils/config.py b/app/core/utils/config.py index e66fdcf1f6..7bcfe01558 100644 --- a/app/core/utils/config.py +++ b/app/core/utils/config.py @@ -309,7 +309,7 @@ def HYPERION_VERSION(cls) -> str: def MINIMAL_TITAN_VERSION_CODE(cls) -> str: with Path("pyproject.toml").open("rb") as pyproject_binary: pyproject = tomllib.load(pyproject_binary) - return str(pyproject["project"]["minimal-titan-version-code"]) + return str(pyproject["tool"]["titan"]["minimal-titan-version-code"]) ###################################### # Automatically generated parameters # diff --git a/pyproject.toml b/pyproject.toml index 826a360703..9a8b75eb08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,6 @@ authors = [{ name = "AEECL ECLAIR" }] # Hyperion follows Semantic Versioning # https://semver.org/ version = "4.9.5" -minimal-titan-version-code = 139 requires-python = ">= 3.11, < 3.13" license = "MIT" @@ -18,6 +17,8 @@ license-files = [ "assets/myeclpay-terms-of-service.txt", ] +[tool.titan] +minimal-titan-version-code = 139 [tool.ruff] # By default ruff also respect gitignore files @@ -26,7 +27,7 @@ line-length = 88 indent-width = 4 target-version = "py311" -[tool.ruff.lint] +[tool.lint] select = [ "FAST", "YTT", @@ -97,7 +98,7 @@ ignore = [ fixable = ["ALL"] unfixable = [] -[tool.ruff.lint.per-file-ignores] +[tool.ruff.per-file-ignores] # Allow `assert` and hardcoded passwords for tests. # Ignore PLW0603 to be able to define global models from init fixture "tests/*" = ["S101", "S105", "S106", "ASYNC230", "PLW0603"] @@ -114,7 +115,7 @@ unfixable = [] # Allow complexe methods for auth endpoints "app/core/auth/endpoints_auth.py" = ["C901"] -[tool.ruff.lint.mccabe] +[tool.ruff.mccabe] # Flag errors (`C901`) whenever the complexity level exceeds 18. max-complexity = 18 @@ -201,3 +202,4 @@ exclude_also = [] skip_covered = true show_missing = true + From 48a15273862a78fc15fa63d64f23829f714f1bb6 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:52:07 +0200 Subject: [PATCH 06/42] About the .env --- .env.template | 2 +- README.md | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/.env.template b/.env.template index 5bd67a6f44..938b46b945 100644 --- a/.env.template +++ b/.env.template @@ -18,7 +18,7 @@ POSTGRES_TZ="Etc/UTC" # We use the default redis configuration, so the protected mode is enabled by default (see https://redis.io/docs/manual/security/#protected-mode) # If you want to use a custom configuration, a password and a specific binds should be used to avoid security issues -# May be left at "" during dev if you don't have a redis server running, in production it should be set to the name of the redis container +# REDIS_HOST may be left at "" to disable Redis during development if you don't have a redis server running, in production it should be set to the name of the redis container REDIS_HOST="hyperion-redis" REDIS_PORT=6379 # Should be commented during development to work with docker-compose-dev, and set in production diff --git a/README.md b/README.md index 0830376be8..db07dbf2a0 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,43 @@ services: volumes: - ./hyperion-db:/var/lib/postgresql/data ``` + +## Complete the dotenv (`.env`) and the `config.yaml` + +Copy the `.env.template` file in a new `.env` file, same for `config.template.yaml` in a new `config.yaml`. +These template files were carefully crafted to work for you with minimal changes to bring, and some preconfigured services. + +For later reference, these settings are documented in [app/core/config.py](./app/core/config.py). +Check this file to know what can and should be set using these two files. + +### `.env` + +The `.env` contains environment variables which need to be accessed by the OS or by other services, such as the database. + +#### With SQLite + +Again there's nothing to do. + +#### With PostgreSQL + +Set your user, password, host and db. + +For instance, with the installer you should have something like: + +```sh +POSTGRES_USER="postgres" +POSTGRES_PASSWORD="" +POSTGRES_HOST="localhost" +POSTGRES_DB="hyperion" +``` + +While with Docker you should have rather something like: + +```sh +POSTGRES_USER="hyperion" +POSTGRES_PASSWORD="" +POSTGRES_HOST="hyperion-db" +POSTGRES_DB="hyperion" ``` ## Launch the API From 9c7996c497d874e52f8c0055b06b1e57fc43cf7d Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:54:17 +0200 Subject: [PATCH 07/42] About config.yaml --- README.md | 21 +++++++++++++++++++++ app/core/utils/config.py | 5 ++--- config.template.yaml | 17 ++++++++++------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index db07dbf2a0..101f993c33 100644 --- a/README.md +++ b/README.md @@ -232,6 +232,27 @@ POSTGRES_HOST="hyperion-db" POSTGRES_DB="hyperion" ``` +### `config.yaml` + +The `config.yaml` contains environment variables that are internal to the Python runtime _because_ they are only used in the Python code. + +1. `ACCESS_TOKEN_SECRET_KEY`: **Uncomment it**. + You can generate your own if you want, or just change a couple characters, or leave it as it is. +2. `RSA_PRIVATE_PEM_STRING`: **Uncomment it**. + You can generate your own if you want, or just change a couple characters, or leave it as it is. +3. `AUTH_CLIENTS`: we already provide you some configuration to run Titan and authenticate to the swagger to use it at its full potential. + The auth clients allow other service to manage accounts and authenticate users using Hyperion ("Login with MyECL") as a SSO (Single-Sign On). +4. `CORS_ORIGINS`: List of URLs that are authorized to contact Hyperion. + _In case you have CORS issues_ with your local Hyperion, we remind you in the comment that you can use `- "*"` to allow all origins. +5. `SQLITE_DB`: **tells Hyperion whether to use SQLite or PostgreSQL**. + - If you use **SQLite**: this field should be a (relative) filename, by default we named it `app.db`, you can change this name. + Hyperion will create this file for you and use it as the database. + Any PostgreSQL-related configuration will be ignored. + - If you use **PostgreSQL**: empty this field. + Hyperion will fallback to PostgreSQL settings. +6. `USE_FACTORIES`: `True` by default, factories seed your database, if empty, with mocked data. + This is useful on SQLite to repopulate your new database after dropping the previous one. + ## Launch the API ```bash diff --git a/app/core/utils/config.py b/app/core/utils/config.py index 7bcfe01558..7d034ead6e 100644 --- a/app/core/utils/config.py +++ b/app/core/utils/config.py @@ -118,10 +118,9 @@ def settings_customise_sources( ############################################### # Authorization using OAuth or Openid connect # ############################################### - - # ACCESS_TOKEN_SECRET_KEY should contain a random string with enough entropy (at least 32 bytes long) to securely sign all access_tokens for OAuth and Openid connect + # ACCESS_TOKEN_SECRET_KEY should contain a strong random string with enough entropy (at least 32 bytes long) to securely sign all JWT access_tokens for OAuth2 and OpenID Connect ACCESS_TOKEN_SECRET_KEY: str - # RSA_PRIVATE_PEM_STRING should be a string containing the PEM certificate of a private RSA key. It will be used to sign id_tokens for Openid connect authentication + # RSA_PRIVATE_PEM_STRING should be a string containing the PEM certificate of a private RSA key. It will be used to sign JWS id_tokens for OpenID Connect authentication # In the pem certificates newlines can be replaced by `\n` RSA_PRIVATE_PEM_STRING: bytes diff --git a/config.template.yaml b/config.template.yaml index 19af2cd525..4aefb06c09 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -1,8 +1,12 @@ ############################################### # Authorization using OAuth or Openid connect # ############################################### + # ACCESS_TOKEN_SECRET_KEY should contain a random string with enough entropy (at least 32 bytes long) to securely sign all access_tokens for OAuth and Openid connect -ACCESS_TOKEN_SECRET_KEY: "" +# If you want to generate a 2048-bit long PEM certificate and save it in a file, the following command may be used: +# openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem +ACCESS_TOKEN_SECRET_KEY: #"YWZOHliiI53lJMJc5BI_WbGbA4GF2T7Wbt1airIhOXEa3c021c4-1c55-4182-b141-7778bcc8fac4" + # RSA_PRIVATE_PEM_STRING should be a string containing the PEM certificate of a private RSA key. It will be used to sign id_tokens for Openid connect authentication # The example below was generated using a 2048-bit RSA key generator RSA_PRIVATE_PEM_STRING: | @@ -80,17 +84,16 @@ AUTH_CLIENTS: # Hyperion settings # ##################### -LOG_DEBUG_MESSAGES: True - # Origins for the CORS middleware. `["http://localhost"]` can be used for development. # See https://fastapi.tiangolo.com/tutorial/cors/ # It should begin with 'http://' or 'https:// and should never end with a '/' CORS_ORIGINS: - http://localhost:3000 - http://127.0.0.1:3000 -# - * +# - "*" -# If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible Postgresql should be used instead) +LOG_DEBUG_MESSAGES: True +# If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) SQLITE_DB: app.db # If True, will print all SQL queries in the console DATABASE_DEBUG: False @@ -107,14 +110,14 @@ SMTP_SERVER: "" SMTP_USERNAME: "" SMTP_PASSWORD: "" SMTP_EMAIL: "" - ########################## # Firebase Configuration # ########################## # To enable Firebase push notification capabilities, a JSON key file named `firebase.json` should be placed at Hyperion root. # This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. -USE_FIREBASE: false +#USE_FIREBASE: False + ######################## # Matrix configuration # ######################## From 682043bc25ac59ac9807d36d9a83fa77e3cee1ac Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:55:53 +0200 Subject: [PATCH 08/42] About launching Hyperion and creating your own admin user --- README.md | 87 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 101f993c33..d8f851112d 100644 --- a/README.md +++ b/README.md @@ -255,53 +255,85 @@ The `config.yaml` contains environment variables that are internal to the Python ## Launch the API +> [!WARNING] +> Beforehand, check that your venv is activated. + +### Using VS Code + +1. In the activity bar (the leftmost part), click the _Run and Debug_ icon (the play button). +2. Click the green play button. + +Check that your Hyperion instance is up and running by navigating to http://localhost:8000/information. + +### Using the command-line interface + ```bash fastapi dev app/main.py ``` -## Use Alembic migrations +Check that your Hyperion instance is up and running by navigating to http://localhost:8000/information. -See [migrations README](./migrations/README) +## Create your own user -Warning : on SQLite databases, you have to drop the database and recreate it to apply the new DDL. +There are many ways to do so, ranked here from easiest (GUI only) to hardest (CLI only). +Note that registration and activation are distinct steps, so for fun you may register one way and activate your account another way. -## OpenAPI specification +### With CalypSSO -API endpoints are parsed following the OpenAPI specifications at `http://127.0.0.1:8000/openapi.json`. +#### Registering your account -A Swagger UI is available at `http://127.0.0.1:8000/docs`. For authentication to work, a valid `AUTH_CLIENT` must be defined in the `.env`, with `http://127.0.0.1:8000/docs/oauth2-redirect` as the redirect URI, and `scope=API` must be added to the authentication request. +Go to http://localhost:8000/calypsso/register and type a valid email address to register (start the creation of) your account. -## Create the first user +#### Activating your account -You can create the first user either using Titan or calling the API directly. +Go back to the shell running your Hyperion instance, in the logs look for a link looking like http://localhost:3000/calypsso/activate?activation_token=12345. +Open it and activate (end the creation of) your account. -> You need to use an email with the format `...@etu.ec-lyon.fr` or `...@ec-lyon.fr` +### With Titan -To activate your account you will need an activation token which will be printed in the console. +1. Click "_Se connecter_" on the login page: you land CalypSSO's login page. +2. Click "_Créer un compte_" and create your account using CalypSSO as above. -### With Titan +### Using the API through the swagger -Press "Créer un compte" on the first page and follow the process. +#### Registering your account -### Using the API directly +1. Go to http://localhost:8000/docs: this is called the _swagger_, a web interface to interact with the API, it is a layer on top of the "automatic documentation" (the _OpenAPI specification_) generated by FastAPI at http://localhost:8000/openapi.json. +2. Search `/users/create`. +3. Open it, click "Try it out". +4. Fill in your email address, and click "Execute". -Create the account: +#### Activating your account + +1. Go back to the shell running your Hyperion instance, in the logs look for a link looking like http://localhost:3000/calypsso/activate?activation_token=12345. +2. Copy this activation token. +3. Go again on the swagger and search `/users/activate`. +4. Open it, click "Try it out". +5. Fill in your information, using the `activation_token` you copied (click "Schema" next to "Edit Value" so see what fields are optional), and click "Execute". + +### Using the API in command line + +> [!TIP] +> On Windows, `curl` is different. +> To get the same results as on Linux and MacOS: +> +> - either replace `curl` with `curl.exe` +> - or run the `curl` commands below in a bash (using WSL or using Git Bash) + +#### Registering your account ```bash -curl --location 'http://127.0.0.1:8000/users/create' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "email": "<...>@etu.ec-lyon.fr", - "account_type": "39691052-2ae5-4e12-99d0-7a9f5f2b0136" -}' +curl --json '{"email": "prenom.nom@etu.ec-lyon.fr"}' http://localhost:8000/users/create ``` -Activate the account: +#### Activating your account + +1. Go back to the shell running your Hyperion instance, in the logs look for a link looking like http://localhost:3000/calypsso/activate?activation_token=12345. +2. Copy this activation token. +3. Use this `activation_token` in: ```bash -curl --location 'http://127.0.0.1:8000/users/activate' \ ---header 'Content-Type: application/json' \ ---data '{ +curl --json '{ "name": "", "firstname": "", "nickname": "", @@ -311,15 +343,18 @@ curl --location 'http://127.0.0.1:8000/users/activate' \ "phone": "", "promo": 0, "floor": "" -}' +}' http://localhost:8000/users/activate ``` ## Make the first user admin +> [!WARNING] +> This may not work if you ran the factories + If there is exactly one user in the database, you can make it admin using the following command: ```bash -curl --location --request POST 'http://127.0.0.1:8000/users/make-admin' +curl -X POST http://localhost:8000/users/make-admin ``` ## Install docker or an equivalent From ef0e129e9251e9d223029503379cd9e9bc973e43 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 21 Sep 2025 18:56:40 +0200 Subject: [PATCH 09/42] Beyond initial config --- README.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8f851112d..e03bf75963 100644 --- a/README.md +++ b/README.md @@ -357,7 +357,11 @@ If there is exactly one user in the database, you can make it admin using the fo curl -X POST http://localhost:8000/users/make-admin ``` -## Install docker or an equivalent +--- + +# Beyond initial configuration + +## Install Docker or an equivalent Install docker and the compose plugin (https://docs.docker.com/compose/install/) @@ -365,7 +369,24 @@ Install docker and the compose plugin (https://docs.docker.com/compose/install/) > During dev, `docker-compose-dev.yaml` can be used to run the database, the redis server etc... If you really want to run the project without docker, you can do it but you will have to install the database, redis, etc ... yourself or disable corresponding features in the .env file (which is not recommended). ---- +## Linting and formating + +To lint and format, we currently use `Ruff`. We also use `Mypy` for the type checking. + +Before each PR or git push you will need to run `ruff check --fix && ruff format` in order to format/lint your code and `mypy .` in order to verify that there is no type mismatch. + +## Use Alembic migrations + +See [migrations README](./migrations/README) + +> [!WARNING] +> On SQLite databases, you have to drop the database and recreate it to apply the new DDL. + +## OpenAPI specification + +API endpoints are parsed following the OpenAPI specifications at `http://127.0.0.1:8000/openapi.json`. + +A Swagger UI is available at `http://127.0.0.1:8000/docs`. For authentication to work, a valid `AUTH_CLIENT` must be defined in the `.env`, with `http://127.0.0.1:8000/docs/oauth2-redirect` as the redirect URI, and `scope=API` must be added to the authentication request. ## Configure Firebase notifications From 223447642b535390210773f44cbc957e48d00c0f Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 22 Sep 2025 08:06:41 +0200 Subject: [PATCH 10/42] Fix(.gitignore): distinguish folders for readability --- .gitignore | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 51feb75a56..d02855758b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,12 @@ # Cache folders -__pycache__ -.mypy_cache -.pytest_cache -.ruff_cache +__pycache__/ +.mypy_cache/ +.pytest_cache/ +.ruff_cache/ -# Databases +# Databases (PostgreSQL and SQLite) +hyperion-db/ *.db -hyperion-db # Persistent data as files data/ @@ -16,11 +16,11 @@ data/ config.yaml firebase.json -# MacOS +# macOS .DS_Store # Virtual environment -.venv +.venv/ # Logs logs/ @@ -30,7 +30,7 @@ logs/ # Jinja output templates and test output tests/jinja_test_outputs/ -node_modules +node_modules/ # Local testing scripts/ From 5cc4a0a2b9b5df56b1bd3550b9ba3f682e093685 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 22 Sep 2025 08:30:17 +0200 Subject: [PATCH 11/42] rm requests, use httpx instead, update requirements --- app/utils/communication/matrix.py | 11 +++++++---- requirements-common.txt | 2 +- requirements-dev.txt | 2 -- tests/test_payment.py | 3 --- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/utils/communication/matrix.py b/app/utils/communication/matrix.py index 566689fea8..ca7699fcc1 100644 --- a/app/utils/communication/matrix.py +++ b/app/utils/communication/matrix.py @@ -1,6 +1,6 @@ from typing import Any -import requests +import httpx from app.types.exceptions import MatrixRequestError, MatrixSendMessageError @@ -24,7 +24,7 @@ def __init__( self.access_token = token - def post( + async def post( self, url: str, json: dict[str, Any], @@ -43,10 +43,13 @@ def post( if "Authorization" not in headers: headers["Authorization"] = "Bearer " + self.access_token - response = requests.post(url, json=json, headers=headers, timeout=10) try: + async with httpx.AsyncClient() as client: + response = await client.post( + url, json=json, headers=headers, timeout=10 + ) response.raise_for_status() - except requests.exceptions.HTTPError as err: + except httpx.RequestError as err: raise MatrixRequestError() from err return response.json() diff --git a/requirements-common.txt b/requirements-common.txt index 538a870a9e..502741928a 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -12,6 +12,7 @@ fastapi[standard]==0.115.6 firebase-admin==6.5.0 # Firebase is used for push notification google-auth-oauthlib==1.2.1 helloasso-python==1.0.5 +httpx==0.27.0 icalendar==5.0.13 jellyfish==1.0.4 # String Matching Jinja2==3.1.6 # template engine for html files @@ -24,7 +25,6 @@ PyMuPDF==1.24.9 # PDF processing, imported as `fitz` pypdf==4.3.1 python-multipart==0.0.18 # a form data parser, as oauth flow requires form-data parameters redis==5.0.8 -requests==2.32.4 sqlalchemy-utils == 0.41.2 SQLAlchemy[asyncio]==2.0.32 # [asyncio] allows greenlet to be installed on Apple M1 devices. unidecode==1.3.8 diff --git a/requirements-dev.txt b/requirements-dev.txt index 5a4cbc8920..bf33a30634 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,7 +2,6 @@ aiosqlite==0.20.0 boto3-stubs[essential]==1.38.23 google-auth-stubs==0.3.0 -httpx==0.27.0 # needed for tests as a replacement of requests in TestClient mypy[faster-cache]==1.16.0 psycopg[binary]==3.2.1 # PostgreSQL adapter for synchronous operations at startup (database initializations & migrations), binary installation is the easiest way to install it pytest-alembic==0.12.1 @@ -16,4 +15,3 @@ types-Authlib==1.5.0.20250516 types-fpdf2==2.8.3.20250516 types-psutil==7.0.0.20250601 types-redis==4.6.0.20241004 -types-requests==2.32.0.20250515 diff --git a/tests/test_payment.py b/tests/test_payment.py index 88cd84264a..33f9af6ebd 100644 --- a/tests/test_payment.py +++ b/tests/test_payment.py @@ -12,7 +12,6 @@ HelloAssoApiV5ModelsCartsInitCheckoutResponse, ) from pytest_mock import MockerFixture -from requests import Response from sqlalchemy.ext.asyncio import AsyncSession from app.core.payment import cruds_payment, models_payment, schemas_payment @@ -495,8 +494,6 @@ def init_a_checkout_side_effect( init_checkout_body: HelloAssoApiV5ModelsCartsInitCheckoutBody, ): if init_checkout_body.payer is not None: - r = Response() - r.status_code = 400 raise UnauthorizedException return HelloAssoApiV5ModelsCartsInitCheckoutResponse( id=7, From c9d1cc22534f3e5e8e18755bf8f2aa359cf039ec Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 22 Sep 2025 09:35:57 +0200 Subject: [PATCH 12/42] Type-checking fixes --- app/core/myeclpay/endpoints_myeclpay.py | 3 --- app/utils/communication/matrix.py | 4 ++-- app/utils/loggers_tools/matrix_handler.py | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/core/myeclpay/endpoints_myeclpay.py b/app/core/myeclpay/endpoints_myeclpay.py index 30f6e30749..1423c4bb97 100644 --- a/app/core/myeclpay/endpoints_myeclpay.py +++ b/app/core/myeclpay/endpoints_myeclpay.py @@ -16,7 +16,6 @@ Query, ) from fastapi.responses import RedirectResponse -from fastapi.templating import Jinja2Templates from sqlalchemy.ext.asyncio import AsyncSession from app.core.core_endpoints import cruds_core @@ -82,8 +81,6 @@ factory=None, ) -templates = Jinja2Templates(directory="assets/templates") - hyperion_error_logger = logging.getLogger("hyperion.error") hyperion_security_logger = logging.getLogger("hyperion.security") diff --git a/app/utils/communication/matrix.py b/app/utils/communication/matrix.py index ca7699fcc1..f50b827c61 100644 --- a/app/utils/communication/matrix.py +++ b/app/utils/communication/matrix.py @@ -54,7 +54,7 @@ async def post( return response.json() - def send_message(self, room_id: str, formatted_body: str) -> None: + async def send_message(self, room_id: str, formatted_body: str) -> None: """ Send a message to the room `room_id`. `formatted_body` can contain html formatted text @@ -74,6 +74,6 @@ def send_message(self, room_id: str, formatted_body: str) -> None: } try: - self.post(url, json=data, headers=None) + await self.post(url, json=data, headers=None) except MatrixRequestError as error: raise MatrixSendMessageError(room_id=room_id) from error diff --git a/app/utils/loggers_tools/matrix_handler.py b/app/utils/loggers_tools/matrix_handler.py index d09d0e6644..abcbcfa281 100644 --- a/app/utils/loggers_tools/matrix_handler.py +++ b/app/utils/loggers_tools/matrix_handler.py @@ -39,12 +39,12 @@ def __init__( ) @override - def emit(self, record): + async def emit(self, record): if self.enabled: msg = self.format(record) try: - self.matrix.send_message(self.room_id, msg) + await self.matrix.send_message(self.room_id, msg) # We should catch and log any error, as Python may discarded them in production except Exception as err: # We use warning level so that the message is not sent to matrix again From 536cb440f1dc77c9dfd5c08e42419a4cf4d86663 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 22 Sep 2025 11:42:57 +0200 Subject: [PATCH 13/42] Feat: async log handler running in a different thread --- app/core/utils/log.py | 4 ++-- app/utils/loggers_tools/matrix_handler.py | 27 +++++++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/app/core/utils/log.py b/app/core/utils/log.py index 8d6d517e74..f6fe2d68d8 100644 --- a/app/core/utils/log.py +++ b/app/core/utils/log.py @@ -78,7 +78,7 @@ class console_color: # Logging config # See https://docs.python.org/3/library/logging.config.html#logging-config-dictschema - def get_config_dict(self, settings: Settings): + def _get_config_dict(self, settings: Settings): # We can't use a dependency to access settings as this function is not an endpoint. The object must thus be passed as a parameter. # /!\ WARNING /!\ @@ -398,7 +398,7 @@ def initialize_loggers(self, settings: Settings): # If logs/ folder does not exist, the logging module won't be able to create file handlers Path("logs/").mkdir(parents=True, exist_ok=True) - config_dict = self.get_config_dict(settings=settings) + config_dict = self._get_config_dict(settings=settings) logging.config.dictConfig(config_dict) loggers = [logging.getLogger(name) for name in config_dict["loggers"]] diff --git a/app/utils/loggers_tools/matrix_handler.py b/app/utils/loggers_tools/matrix_handler.py index abcbcfa281..e978c2edaf 100644 --- a/app/utils/loggers_tools/matrix_handler.py +++ b/app/utils/loggers_tools/matrix_handler.py @@ -1,3 +1,4 @@ +import asyncio import logging from logging import StreamHandler @@ -37,17 +38,25 @@ def __init__( token=token, server_base_url=server_base_url, ) + self.loop = asyncio.new_event_loop() @override - async def emit(self, record): + def emit(self, record): if self.enabled: msg = self.format(record) + self.loop.create_task(self._emit(msg)) + + async def _emit(self, msg): + try: + await self.matrix.send_message(self.room_id, msg) + # We should catch and log any error, as Python may discarded them in production + except Exception as err: + # We use warning level so that the message is not sent to matrix again + hyperion_error_logger.warning( + f"MatrixHandler: Unable to send message to Matrix server: {err}", + ) - try: - await self.matrix.send_message(self.room_id, msg) - # We should catch and log any error, as Python may discarded them in production - except Exception as err: - # We use warning level so that the message is not sent to matrix again - hyperion_error_logger.warning( - f"MatrixHandler: Unable to send message to Matrix server: {err}", - ) + @override + def close(self) -> None: + self.loop.run_until_complete(asyncio.gather(*asyncio.all_tasks(self.loop))) + self.loop.close() From f27b2b207eae2035568e85e368adafdda6eb869a Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 22 Sep 2025 12:10:29 +0200 Subject: [PATCH 14/42] re-run tests --- app/utils/loggers_tools/matrix_handler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/utils/loggers_tools/matrix_handler.py b/app/utils/loggers_tools/matrix_handler.py index e978c2edaf..9d1467e65e 100644 --- a/app/utils/loggers_tools/matrix_handler.py +++ b/app/utils/loggers_tools/matrix_handler.py @@ -33,12 +33,12 @@ def __init__( self.room_id = room_id self.enabled = enabled + self.loop = asyncio.new_event_loop() if self.enabled: self.matrix = Matrix( token=token, server_base_url=server_base_url, ) - self.loop = asyncio.new_event_loop() @override def emit(self, record): @@ -57,6 +57,6 @@ async def _emit(self, msg): ) @override - def close(self) -> None: + def close(self): self.loop.run_until_complete(asyncio.gather(*asyncio.all_tasks(self.loop))) self.loop.close() From bcb94ce33401f32a58d13592bb3e2f79a121549d Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 22 Sep 2025 14:46:26 +0200 Subject: [PATCH 15/42] Feat: use the scheduler to synchronically defer writing the logs --- app/core/utils/log.py | 3 +++ app/utils/loggers_tools/matrix_handler.py | 31 ++++++++++------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/app/core/utils/log.py b/app/core/utils/log.py index f6fe2d68d8..02c5695201 100644 --- a/app/core/utils/log.py +++ b/app/core/utils/log.py @@ -7,6 +7,7 @@ from typing import Any import uvicorn +from fastapi import BackgroundTasks from app.core.utils.config import Settings @@ -121,6 +122,7 @@ def _get_config_dict(self, settings: Settings): # Send error to a Matrix server. If credentials are not set in settings, the handler will be disabled "formatter": "matrix", "class": "app.utils.loggers_tools.matrix_handler.MatrixHandler", + "background_tasks": BackgroundTasks, "room_id": settings.MATRIX_LOG_ERROR_ROOM_ID, "token": settings.MATRIX_TOKEN, "server_base_url": settings.MATRIX_SERVER_BASE_URL, @@ -133,6 +135,7 @@ def _get_config_dict(self, settings: Settings): # Send error to a Matrix server. If credentials are not set in settings, the handler will be disabled "formatter": "matrix", "class": "app.utils.loggers_tools.matrix_handler.MatrixHandler", + "background_tasks": BackgroundTasks, "room_id": settings.MATRIX_LOG_AMAP_ROOM_ID, "token": settings.MATRIX_TOKEN, "server_base_url": settings.MATRIX_SERVER_BASE_URL, diff --git a/app/utils/loggers_tools/matrix_handler.py b/app/utils/loggers_tools/matrix_handler.py index 9d1467e65e..15c5e810d0 100644 --- a/app/utils/loggers_tools/matrix_handler.py +++ b/app/utils/loggers_tools/matrix_handler.py @@ -1,7 +1,7 @@ -import asyncio import logging from logging import StreamHandler +from fastapi import BackgroundTasks from typing_extensions import override from app.utils.communication.matrix import Matrix @@ -22,6 +22,7 @@ class MatrixHandler(StreamHandler): def __init__( self, + background_tasks: BackgroundTasks, room_id: str, token: str, server_base_url: str | None, @@ -31,9 +32,9 @@ def __init__( super().__init__() self.setLevel(level) + self.background_tasks = background_tasks self.room_id = room_id self.enabled = enabled - self.loop = asyncio.new_event_loop() if self.enabled: self.matrix = Matrix( token=token, @@ -44,19 +45,13 @@ def __init__( def emit(self, record): if self.enabled: msg = self.format(record) - self.loop.create_task(self._emit(msg)) - - async def _emit(self, msg): - try: - await self.matrix.send_message(self.room_id, msg) - # We should catch and log any error, as Python may discarded them in production - except Exception as err: - # We use warning level so that the message is not sent to matrix again - hyperion_error_logger.warning( - f"MatrixHandler: Unable to send message to Matrix server: {err}", - ) - - @override - def close(self): - self.loop.run_until_complete(asyncio.gather(*asyncio.all_tasks(self.loop))) - self.loop.close() + try: + self.background_tasks.add_task( + self.matrix.send_message, room_id=self.room_id, formatted_body=msg + ) + # We should catch and log any error, as Python may discarded them in production + except Exception as err: + # We use warning level so that the message is not sent to matrix again + hyperion_error_logger.warning( + f"MatrixHandler: Unable to send message to Matrix server: {err}", + ) From 5515ac857028085c8a9436cd56e94f2981645fc1 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 6 Oct 2025 00:41:59 +0200 Subject: [PATCH 16/42] Details feats on config.yaml --- README.md | 21 ++++++++++++--------- config.template.yaml | 11 ++++++----- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index e03bf75963..9337c5e5f8 100644 --- a/README.md +++ b/README.md @@ -151,9 +151,13 @@ None (not so heavy, configuration not so hard). 4. Create a database named `hyperion` ```sh -psql -U postgres -c "CREATE DATABASE hyperion;" +psql -U postgres -c "create database hyperion;" ``` +> [!TIP] +> SQL keywords are case-insensitive by convention. +> No need to write `CREATE DATABASE hyperion;` + Now your Hyperion database can be explored by hand (as the `postgres` user, using your password you chose) with: ```bash @@ -196,8 +200,11 @@ services: ## Complete the dotenv (`.env`) and the `config.yaml` -Copy the `.env.template` file in a new `.env` file, same for `config.template.yaml` in a new `config.yaml`. -These template files were carefully crafted to work for you with minimal changes to bring, and some preconfigured services. +> [!IMPORTANT] +> Copy the `.env.template` file in a new `.env` file, likewise copy `config.template.yaml` in a new `config.yaml`. + +> [!TIP] +> These template files were carefully crafted to work for you with minimal personal changes to bring, and some preconfigured services. For later reference, these settings are documented in [app/core/config.py](./app/core/config.py). Check this file to know what can and should be set using these two files. @@ -240,17 +247,13 @@ The `config.yaml` contains environment variables that are internal to the Python You can generate your own if you want, or just change a couple characters, or leave it as it is. 2. `RSA_PRIVATE_PEM_STRING`: **Uncomment it**. You can generate your own if you want, or just change a couple characters, or leave it as it is. -3. `AUTH_CLIENTS`: we already provide you some configuration to run Titan and authenticate to the swagger to use it at its full potential. - The auth clients allow other service to manage accounts and authenticate users using Hyperion ("Login with MyECL") as a SSO (Single-Sign On). -4. `CORS_ORIGINS`: List of URLs that are authorized to contact Hyperion. - _In case you have CORS issues_ with your local Hyperion, we remind you in the comment that you can use `- "*"` to allow all origins. -5. `SQLITE_DB`: **tells Hyperion whether to use SQLite or PostgreSQL**. +3. `SQLITE_DB`: **tells Hyperion whether to use SQLite or PostgreSQL**. - If you use **SQLite**: this field should be a (relative) filename, by default we named it `app.db`, you can change this name. Hyperion will create this file for you and use it as the database. Any PostgreSQL-related configuration will be ignored. - If you use **PostgreSQL**: empty this field. Hyperion will fallback to PostgreSQL settings. -6. `USE_FACTORIES`: `True` by default, factories seed your database, if empty, with mocked data. +4. `USE_FACTORIES`: `True` by default, factories seed your database, if empty, with mocked data. This is useful on SQLite to repopulate your new database after dropping the previous one. ## Launch the API diff --git a/config.template.yaml b/config.template.yaml index 4aefb06c09..2d4daae016 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -84,15 +84,16 @@ AUTH_CLIENTS: # Hyperion settings # ##################### -# Origins for the CORS middleware. `["http://localhost"]` can be used for development. +# Origins for the CORS middleware. `["http://localhost:3000"]` can be used for development. # See https://fastapi.tiangolo.com/tutorial/cors/ # It should begin with 'http://' or 'https:// and should never end with a '/' +# For a local instance, using a wildcard "*" is convenient CORS_ORIGINS: - - http://localhost:3000 - - http://127.0.0.1:3000 -# - "*" + - "*" +# - http://localhost:3000 +# - http://127.0.0.1:3000 -LOG_DEBUG_MESSAGES: True +LOG_DEBUG_MESSAGES: False # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) SQLITE_DB: app.db # If True, will print all SQL queries in the console From 1b5699a6cab39dba87855824cefc770577119704 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 6 Oct 2025 00:43:06 +0200 Subject: [PATCH 17/42] Feat: fastapi's arg "app/main.py" is useless --- .vscode/launch.json | 2 +- Dockerfile | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d6f3ab8e55..defabec9ab 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "debugpy", "request": "launch", "module": "fastapi_cli", - "args": ["dev", "app/main.py"], + "args": ["dev"], "jinja": true, "justMyCode": true } diff --git a/Dockerfile b/Dockerfile index cfe13efa1a..f1968e12e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,4 +15,4 @@ COPY migrations migrations/ COPY assets assets/ COPY app app/ -ENTRYPOINT fastapi run app/main.py --workers "${NB_WORKERS:-1}" \ No newline at end of file +ENTRYPOINT fastapi run --workers "${NB_WORKERS:-1}" \ No newline at end of file diff --git a/README.md b/README.md index 9337c5e5f8..d18dd86e27 100644 --- a/README.md +++ b/README.md @@ -271,7 +271,7 @@ Check that your Hyperion instance is up and running by navigating to http://loca ### Using the command-line interface ```bash -fastapi dev app/main.py +fastapi dev ``` Check that your Hyperion instance is up and running by navigating to http://localhost:8000/information. From aa1bc8fa7225a79627e41fe7db15cd100f30119d Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 6 Oct 2025 00:44:11 +0200 Subject: [PATCH 18/42] Feat: psycopg[binary] as a common requirement --- .github/workflows/publish.yml | 12 ++++++------ .github/workflows/publishbase.yml | 8 +++----- Dockerfile.base | 3 +-- requirements-common.txt | 3 ++- requirements-dev.txt | 1 - requirements-prod.txt | 2 -- 6 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 requirements-prod.txt diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9094d6dbca..88883360fb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: push: tags: - - 'v*.*.*' + - "v*.*.*" jobs: docker: @@ -16,22 +16,22 @@ jobs: - name: Calculate requirements md5 run: | - echo "REQUIREMENTS_MD5=$(cat requirements-common.txt requirements-prod.txt | md5sum | cut -d ' ' -f 1)" >> $GITHUB_ENV - + echo "REQUIREMENTS_MD5=$(cat requirements-common.txt | md5sum | cut -d ' ' -f 1)" >> $GITHUB_ENV + - name: Check if base image exists run: | HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ -u ${{ secrets.DOCKER_REGISTRY_USERNAME }}:${{ secrets.DOCKER_REGISTRY_PASSWORD }} \ -H "Accept: application/vnd.oci.image.index.v1+json" \ "${{ secrets.DOCKER_REGISTRY_URL }}/v2/hyperion-base/manifests/${{ env.REQUIREMENTS_MD5 }}") - + echo "HTTP_CODE=$HTTP_CODE" >> $GITHUB_ENV - + if [ "$HTTP_CODE" -ne 200 ]; then echo "Error: Base image not found, wait for the base image to be built first" exit 1 fi - + echo "EXISTS=true" >> $GITHUB_ENV - name: Docker metadata diff --git a/.github/workflows/publishbase.yml b/.github/workflows/publishbase.yml index e3f27de003..9e52cc81c3 100644 --- a/.github/workflows/publishbase.yml +++ b/.github/workflows/publishbase.yml @@ -3,10 +3,8 @@ on: workflow_dispatch: push: paths: - - 'Dockerfile.base' - - 'requirements-common.txt' - - 'requirements-prod.txt' - + - "Dockerfile.base" + - "requirements-common.txt" jobs: docker: @@ -19,7 +17,7 @@ jobs: - name: Calculate requirements md5 run: | - echo "REQUIREMENTS_MD5=$(cat requirements-common.txt requirements-prod.txt | md5sum | cut -d ' ' -f 1)" >> $GITHUB_ENV + echo "REQUIREMENTS_MD5=$(cat requirements-common.txt | md5sum | cut -d ' ' -f 1)" >> $GITHUB_ENV - name: Check if image exists run: | diff --git a/Dockerfile.base b/Dockerfile.base index 65d462497d..17d71380db 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -7,7 +7,6 @@ ENV UV_COMPILE_BYTECODE=1 WORKDIR /hyperion COPY requirements-common.txt . -COPY requirements-prod.txt . -RUN uv pip install --system --no-cache-dir -r requirements-prod.txt +RUN uv pip install --system --no-cache-dir -r requirements-common.txt ENTRYPOINT ["/bin/bash"] \ No newline at end of file diff --git a/requirements-common.txt b/requirements-common.txt index 502741928a..1644e377eb 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,7 +1,7 @@ aiofiles==24.1.0 # Asynchronous file manipulation alembic==1.13.2 # database migrations arq==0.26.3 # Scheduler -asyncpg==0.29.0 # PostgreSQL adapter for asynchronous operations +asyncpg==0.29.0 # PostgreSQL adapter for *asynchronous* operations authlib==1.6.4 bcrypt==4.1.3 # password hashing boto3==1.38.23 @@ -18,6 +18,7 @@ jellyfish==1.0.4 # String Matching Jinja2==3.1.6 # template engine for html files phonenumbers==8.13.43 # Used for phone number validation psutil==7.0.0 # psutil is used to determine the number of Hyperion workers +psycopg[binary]==3.2.10 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) pydantic-settings==2.3.4 pydantic==2.7.4 pyjwt[crypto]==2.8.0 # generate and verify the JWT tokens, imported as `jwt` diff --git a/requirements-dev.txt b/requirements-dev.txt index bf33a30634..c21a3be872 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,7 +3,6 @@ aiosqlite==0.20.0 boto3-stubs[essential]==1.38.23 google-auth-stubs==0.3.0 mypy[faster-cache]==1.16.0 -psycopg[binary]==3.2.1 # PostgreSQL adapter for synchronous operations at startup (database initializations & migrations), binary installation is the easiest way to install it pytest-alembic==0.12.1 pytest-asyncio==0.26.0 pytest-cov==6.1.1 diff --git a/requirements-prod.txt b/requirements-prod.txt deleted file mode 100644 index a305b4b455..0000000000 --- a/requirements-prod.txt +++ /dev/null @@ -1,2 +0,0 @@ --r requirements-common.txt -psycopg[c]==3.1.19 # PostgreSQL adapter for synchronous operations at startup (database initializations & migrations), local installation is recommended for a production site \ No newline at end of file From d10e22c305ee3d1cc77f88892467b0127da00f22 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 6 Oct 2025 00:49:20 +0200 Subject: [PATCH 19/42] =?UTF-8?q?Feat:=20n=C2=B0=20on=20great=20steps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d18dd86e27..b6527477ea 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Hyperion is the API of an open-source project launched by ÉCLAIR, the computer The structure of this project is modular. Hyperion has a core that performs vital functions (authentication, database migration, authorization, etc). The other functions of Hyperion are realized in what we call modules. You can contribute to the project by adding modules if you wish. -## Creating a virtual environment for Python 3.12 +## 1. Creating a virtual environment for Python 3.12 ### Windows @@ -66,7 +66,7 @@ Activate it pyenv activate hyperion ``` -## Install dependencies +## 2. Install dependencies ### About Jellyfish and Rust @@ -98,7 +98,7 @@ jellyfish==1.0.4 # String Matching > If you need to remove all modules from your virtual environnement, delete your `.venv` folder. -## Install and configure a database +## 3. Install and configure a database Choose either SQLite or PostgreSQL. @@ -198,7 +198,7 @@ services: - ./hyperion-db:/var/lib/postgresql/data ``` -## Complete the dotenv (`.env`) and the `config.yaml` +## 4. Complete the dotenv (`.env`) and the `config.yaml` > [!IMPORTANT] > Copy the `.env.template` file in a new `.env` file, likewise copy `config.template.yaml` in a new `config.yaml`. @@ -256,7 +256,7 @@ The `config.yaml` contains environment variables that are internal to the Python 4. `USE_FACTORIES`: `True` by default, factories seed your database, if empty, with mocked data. This is useful on SQLite to repopulate your new database after dropping the previous one. -## Launch the API +## 5. Launch the API > [!WARNING] > Beforehand, check that your venv is activated. @@ -276,7 +276,7 @@ fastapi dev Check that your Hyperion instance is up and running by navigating to http://localhost:8000/information. -## Create your own user +## 6. Create your own user There are many ways to do so, ranked here from easiest (GUI only) to hardest (CLI only). Note that registration and activation are distinct steps, so for fun you may register one way and activate your account another way. @@ -349,7 +349,7 @@ curl --json '{ }' http://localhost:8000/users/activate ``` -## Make the first user admin +## 7. Make the first user admin > [!WARNING] > This may not work if you ran the factories From 4fe4ffe3db59292e84422d71ba2305800e982b30 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 6 Oct 2025 01:03:52 +0200 Subject: [PATCH 20/42] Fix: REDIS_HOST false-ish values to disable it --- .env.template | 4 ++-- app/core/utils/config.py | 2 +- app/utils/state.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.env.template b/.env.template index 938b46b945..3413bec54b 100644 --- a/.env.template +++ b/.env.template @@ -18,8 +18,8 @@ POSTGRES_TZ="Etc/UTC" # We use the default redis configuration, so the protected mode is enabled by default (see https://redis.io/docs/manual/security/#protected-mode) # If you want to use a custom configuration, a password and a specific binds should be used to avoid security issues -# REDIS_HOST may be left at "" to disable Redis during development if you don't have a redis server running, in production it should be set to the name of the redis container -REDIS_HOST="hyperion-redis" +# REDIS_HOST may be commented to disable Redis during development if you don't have a redis server running, in production it should be set to the name of the redis container +#REDIS_HOST="localhost" REDIS_PORT=6379 # Should be commented during development to work with docker-compose-dev, and set in production #REDIS_PASSWORD="" diff --git a/app/core/utils/config.py b/app/core/utils/config.py index 7d034ead6e..1ad5fb5052 100644 --- a/app/core/utils/config.py +++ b/app/core/utils/config.py @@ -385,7 +385,7 @@ def OIDC_ISSUER(cls) -> str: @computed_field # type: ignore[prop-decorator] @cached_property def REDIS_URL(cls) -> str | None: - if cls.REDIS_HOST: + if cls.REDIS_HOST is not None and cls.REDIS_HOST != "": # We need to include `:` before the password return ( f"redis://:{cls.REDIS_PASSWORD or ''}@{cls.REDIS_HOST}:{cls.REDIS_PORT}" diff --git a/app/utils/state.py b/app/utils/state.py index f5e109e9f8..c457e58e6c 100644 --- a/app/utils/state.py +++ b/app/utils/state.py @@ -85,7 +85,7 @@ def init_redis_client( Returns None if Redis is not configured. """ redis_client: redis.Redis | None = None - if settings.REDIS_HOST: + if settings.REDIS_HOST is not None and settings.REDIS_HOST != "": try: redis_client = redis.Redis( host=settings.REDIS_HOST, @@ -110,7 +110,7 @@ async def init_scheduler( settings: Settings, _dependency_overrides: dict[Callable[..., Any], Callable[..., Any]], ) -> Scheduler: - if settings.REDIS_HOST: + if settings.REDIS_HOST is not None and settings.REDIS_HOST != "": scheduler = Scheduler() await scheduler.start( From b5579b9bf4deea29937fbe1e9ed45538f9435be8 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 6 Oct 2025 15:32:26 +0200 Subject: [PATCH 21/42] Test: expandable parts --- README.md | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/README.md b/README.md index b6527477ea..b89baa23ac 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,13 @@ The structure of this project is modular. Hyperion has a core that performs vita ## 1. Creating a virtual environment for Python 3.12 +
+ + ### Windows + + Create the virtual environment > You need to be in Hyperion main folder @@ -38,8 +43,15 @@ Activate it .\.venv\Scripts\activate ``` +
+ +
+ + ### macOS (using Pyenv) + + Install Pyenv ```bash @@ -66,6 +78,8 @@ Activate it pyenv activate hyperion ``` +
+ ## 2. Install dependencies ### About Jellyfish and Rust @@ -140,8 +154,13 @@ None (not so heavy, configuration not so hard). #### Configuration +
+ + ##### Without Docker: native binaries + + 1. Download the installer: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads 2. Launch it and trust the wizard - Keep the default folders and ports, install it all, etc... @@ -170,8 +189,15 @@ then running SQL or Postgres commands in this shell, or psql -U postgres -d hyperion -c "select firstname from core_user;" ``` +
+ +
+ + ##### With Docker + + > [!WARNING] > Work in progress @@ -198,6 +224,8 @@ services: - ./hyperion-db:/var/lib/postgresql/data ``` +
+ ## 4. Complete the dotenv (`.env`) and the `config.yaml` > [!IMPORTANT] @@ -217,8 +245,13 @@ The `.env` contains environment variables which need to be accessed by the OS or Again there's nothing to do. +
+ + #### With PostgreSQL + + Set your user, password, host and db. For instance, with the installer you should have something like: @@ -239,6 +272,8 @@ POSTGRES_HOST="hyperion-db" POSTGRES_DB="hyperion" ``` +
+ ### `config.yaml` The `config.yaml` contains environment variables that are internal to the Python runtime _because_ they are only used in the Python code. @@ -281,8 +316,13 @@ Check that your Hyperion instance is up and running by navigating to http://loca There are many ways to do so, ranked here from easiest (GUI only) to hardest (CLI only). Note that registration and activation are distinct steps, so for fun you may register one way and activate your account another way. +
+ + ### With CalypSSO + + #### Registering your account Go to http://localhost:8000/calypsso/register and type a valid email address to register (start the creation of) your account. @@ -292,13 +332,27 @@ Go to http://localhost:8000/calypsso/register and type a valid email address to Go back to the shell running your Hyperion instance, in the logs look for a link looking like http://localhost:3000/calypsso/activate?activation_token=12345. Open it and activate (end the creation of) your account. +
+ +
+ + ### With Titan + + 1. Click "_Se connecter_" on the login page: you land CalypSSO's login page. 2. Click "_Créer un compte_" and create your account using CalypSSO as above. +
+ +
+ + ### Using the API through the swagger + + #### Registering your account 1. Go to http://localhost:8000/docs: this is called the _swagger_, a web interface to interact with the API, it is a layer on top of the "automatic documentation" (the _OpenAPI specification_) generated by FastAPI at http://localhost:8000/openapi.json. @@ -314,8 +368,15 @@ Open it and activate (end the creation of) your account. 4. Open it, click "Try it out". 5. Fill in your information, using the `activation_token` you copied (click "Schema" next to "Edit Value" so see what fields are optional), and click "Execute". +
+ +
+ + ### Using the API in command line + + > [!TIP] > On Windows, `curl` is different. > To get the same results as on Linux and MacOS: @@ -349,6 +410,8 @@ curl --json '{ }' http://localhost:8000/users/activate ``` +
+ ## 7. Make the first user admin > [!WARNING] @@ -362,8 +425,13 @@ curl -X POST http://localhost:8000/users/make-admin --- +
+ + # Beyond initial configuration + + ## Install Docker or an equivalent Install docker and the compose plugin (https://docs.docker.com/compose/install/) @@ -419,3 +487,5 @@ See [app/core/google_api/README.md](./app/core/google_api/README.md) for more in For production we encourage to use multiple Uvicorn workers. You can use our [docker image](./Dockerfile) and [docker-compose file](./docker-compose.yaml) files to run Hyperion with Unicorn. You should use our [init file](./init.py) to ensure that database initialization and migrations are only run once. + +
From c514e9cb13951aebb9946356faf61803b494c030 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 7 Oct 2025 01:32:07 +0200 Subject: [PATCH 22/42] Minor completions --- config.template.yaml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/config.template.yaml b/config.template.yaml index 2d4daae016..c499be764e 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -111,13 +111,14 @@ SMTP_SERVER: "" SMTP_USERNAME: "" SMTP_PASSWORD: "" SMTP_EMAIL: "" + ########################## # Firebase Configuration # ########################## # To enable Firebase push notification capabilities, a JSON key file named `firebase.json` should be placed at Hyperion root. # This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. -#USE_FIREBASE: False +USE_FIREBASE: False ######################## # Matrix configuration # @@ -128,9 +129,9 @@ SMTP_EMAIL: "" # If the following parameters are not set, logging won't use the Matrix handler # MATRIX_SERVER_BASE_URL is optional, the official Matrix server will be used if not configured # Advanced note: Username and password will be used to ask for an access token. A Matrix custom client `Hyperion` is used to make all requests -#MATRIX_SERVER_BASE_URL: "" -#MATRIX_TOKEN: "" -#MATRIX_LOG_ERROR_ROOM_ID: "" +#MATRIX_SERVER_BASE_URL: "https://matrix.example.org/" +#MATRIX_TOKEN: "mct_..." +#MATRIX_LOG_ERROR_ROOM_ID: "!...:myecl.fr" #MATRIX_LOG_AMAP_ROOM_ID: "" ############################# @@ -176,16 +177,21 @@ SMTP_EMAIL: "" # HELLOASSO_API_BASE should have the format: `api.helloasso-sandbox.com` # HelloAsso only allow 20 simultaneous active access token. Note that each Hyperion worker will need its own access token. -# [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] -#HELLOASSO_CONFIGURATIONS: [] -#HELLOASSO_API_BASE: "" +#HELLOASSO_CONFIGURATIONS: # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] +# MYECLPAY: +# helloasso_client_id: ... +# helloasso_client_secret: ... +# helloasso_slug: "AEECL" +# redirection_uri: null +#HELLOASSO_API_BASE: "api.helloasso-sandbox.com" # Maximum wallet balance for MyECLPay in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value -#MYECLPAY_MAXIMUM_WALLET_BALANCE: 1000 +#MYECLPAY_MAXIMUM_WALLET_BALANCE: 8000 # Trusted urls is a list of redirect payment url that can be trusted by Hyperion. # These urls will be used to validate the redirect url provided by the front -#TRUSTED_PAYMENT_REDIRECT_URLS: [] +#TRUSTED_PAYMENT_REDIRECT_URLS: +# - http://localhost:3000/static.html # MyECLPay requires an external service to recurrently check for transactions and state integrity, this service needs an access to all the data related to the transactions and the users involved # This service will use a special token to access the data From 262bc4c9bfb0344158510a6dbd195243e57250b3 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 7 Oct 2025 01:36:53 +0200 Subject: [PATCH 23/42] YAML inline comments; mv CORS_ORIGINS up to auth section --- config.template.yaml | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/config.template.yaml b/config.template.yaml index c499be764e..b12cccd0b9 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -38,32 +38,36 @@ RSA_PRIVATE_PEM_STRING: | #8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= #-----END RSA PRIVATE KEY----- -# Host or url of the instance of Hyperion -# This url will be especially used for oidc/oauth2 discovery endpoint and links send by email -# NOTE: A trailing / is required -CLIENT_URL: http://127.0.0.1:8000/ +# Host or URL of the instance of Hyperion +# This url will be especially used for OIDC/OAuth2 discovery endpoint and links send by email +CLIENT_URL: http://127.0.0.1:8000/ # NOTE: A trailing / is required # Sometimes, when running third services with oidc inside Docker containers, and running Hyperion on your local device # you may need to use a different url for call made from docker and call made from your device # For exemple: -# you will access the login page from your browser http://localhost:8000/auth/authorize -# but the docker container should call http://host.docker.internal:8000/auth/token and not your localhost address -# NOTE: A trailing / is required -#OVERRIDDEN_CLIENT_URL_FOR_OIDC: "http://host.docker.internal:8000/" +# - you will access the login page from your browser http://localhost:8000/auth/authorize +# - but the docker container should call http://host.docker.internal:8000/auth/token and not your localhost address +#OVERRIDDEN_CLIENT_URL_FOR_OIDC: "http://host.docker.internal:8000/" # NOTE: A trailing / is required # Configure AuthClients, to allow services to authenticate users using OAuth2 or Openid connect # The following format should be used in yaml config files: +# Origins for the CORS middleware. `["http://localhost:3000"]` can be used for development. +# See https://fastapi.tiangolo.com/tutorial/cors/ +# It should begin with 'http://' or 'https:// and should never end with a '/' +CORS_ORIGINS: + - "*" # For a local instance, using a wildcard "*" is convenient +# - http://localhost:3000 +# - http://127.0.0.1:3000 # ```yml # AUTH_CLIENTS: # : -# secret: +# secret: (or to use PKCE instead of a client secret) # redirect_uri: # - # - # auth_client: # ``` # `AuthClientClassName` should be a class from `app.utils.auth.providers` -# `secret` may be omitted to use PKCE instead of a client secret AUTH_CLIENTS: Titan: secret: @@ -84,20 +88,9 @@ AUTH_CLIENTS: # Hyperion settings # ##################### -# Origins for the CORS middleware. `["http://localhost:3000"]` can be used for development. -# See https://fastapi.tiangolo.com/tutorial/cors/ -# It should begin with 'http://' or 'https:// and should never end with a '/' -# For a local instance, using a wildcard "*" is convenient -CORS_ORIGINS: - - "*" -# - http://localhost:3000 -# - http://127.0.0.1:3000 - +SQLITE_DB: app.db # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) +DATABASE_DEBUG: False # If True, will print all SQL queries in the console LOG_DEBUG_MESSAGES: False -# If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) -SQLITE_DB: app.db -# If True, will print all SQL queries in the console -DATABASE_DEBUG: False # if True and the database is empty, it will be seeded with mocked data USE_FACTORIES: True From a3434784c3c16f66e3c8be4e8305bbaad917ef60 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 7 Oct 2025 14:45:14 +0200 Subject: [PATCH 24/42] Test: use a .gitguardian.yaml --- .gitguardian.yaml | 40 +++++++++++++++++++++++++++++++ config.template.yaml | 56 ++++++++++++++++++++++---------------------- 2 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 .gitguardian.yaml diff --git a/.gitguardian.yaml b/.gitguardian.yaml new file mode 100644 index 0000000000..086ec06d51 --- /dev/null +++ b/.gitguardian.yaml @@ -0,0 +1,40 @@ +version: 2 + +secret: + show_secrets: true # super annoying to find what is wrong otherwise + + ignored_paths: + - config.template.yaml + + ignored_matches: + - name: ACCESS_TOKEN_SECRET_KEY + match: cb1a54fe4af5b5d7d710946fe1ff3698a1e9ae14b964cb652eae52336b2ef5ac + - name: RSA_PRIVATE_PEM_STRING + match: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k + iClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN + x0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto + W9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR + 9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+ + VAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/ + kYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ + OKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L + H9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA + rro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh + Kui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF + vvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN + i0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE + xjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt + CHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h + DygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4 + EX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c + //Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC + kqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr + kQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2 + 6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA + 0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi + 1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb + nADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32 + 8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= + -----END RSA PRIVATE KEY----- diff --git a/config.template.yaml b/config.template.yaml index b12cccd0b9..14cc889d6a 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -5,38 +5,38 @@ # ACCESS_TOKEN_SECRET_KEY should contain a random string with enough entropy (at least 32 bytes long) to securely sign all access_tokens for OAuth and Openid connect # If you want to generate a 2048-bit long PEM certificate and save it in a file, the following command may be used: # openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem -ACCESS_TOKEN_SECRET_KEY: #"YWZOHliiI53lJMJc5BI_WbGbA4GF2T7Wbt1airIhOXEa3c021c4-1c55-4182-b141-7778bcc8fac4" +ACCESS_TOKEN_SECRET_KEY: YWZOHliiI53lJMJc5BI_WbGbA4GF2T7Wbt1airIhOXEa3c021c4-1c55-4182-b141-7778bcc8fac4 # RSA_PRIVATE_PEM_STRING should be a string containing the PEM certificate of a private RSA key. It will be used to sign id_tokens for Openid connect authentication # The example below was generated using a 2048-bit RSA key generator RSA_PRIVATE_PEM_STRING: | - #-----BEGIN RSA PRIVATE KEY----- - #MIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k - #iClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN - #x0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto - #W9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR - #9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+ - #VAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/ - #kYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ - #OKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L - #H9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA - #rro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh - #Kui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF - #vvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN - #i0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE - #xjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt - #CHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h - #DygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4 - #EX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c - #//Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC - #kqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr - #kQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2 - #6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA - #0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi - #1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb - #nADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32 - #8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= - #-----END RSA PRIVATE KEY----- + -----BEGIN RSA PRIVATE KEY----- + MIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k + iClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN + x0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto + W9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR + 9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+ + VAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/ + kYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ + OKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L + H9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA + rro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh + Kui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF + vvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN + i0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE + xjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt + CHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h + DygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4 + EX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c + //Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC + kqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr + kQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2 + 6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA + 0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi + 1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb + nADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32 + 8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= + -----END RSA PRIVATE KEY----- # Host or URL of the instance of Hyperion # This url will be especially used for OIDC/OAuth2 discovery endpoint and links send by email From 5904cbaba978552019c5d1f4dd737083e35813d0 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 7 Oct 2025 02:12:43 +0200 Subject: [PATCH 25/42] use FACTORIES_DEMO_USERS; rework README with that; Factories and Auth Clients full sections in config.yaml; --- README.md | 72 +++++++++++++++++++++++++++++++++++++------- config.template.yaml | 58 ++++++++++++++++++++++++++++++++--- 2 files changed, 114 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b89baa23ac..6d1f8d6576 100644 --- a/README.md +++ b/README.md @@ -231,13 +231,17 @@ services: > [!IMPORTANT] > Copy the `.env.template` file in a new `.env` file, likewise copy `config.template.yaml` in a new `config.yaml`. +```bash +cp .env.template .env && cp config.template.yaml config.yaml +``` + > [!TIP] > These template files were carefully crafted to work for you with minimal personal changes to bring, and some preconfigured services. For later reference, these settings are documented in [app/core/config.py](./app/core/config.py). Check this file to know what can and should be set using these two files. -### `.env` +### The `.env` file The `.env` contains environment variables which need to be accessed by the OS or by other services, such as the database. @@ -274,7 +278,7 @@ POSTGRES_DB="hyperion" -### `config.yaml` +### The `config.yaml` file The `config.yaml` contains environment variables that are internal to the Python runtime _because_ they are only used in the Python code. @@ -289,7 +293,10 @@ The `config.yaml` contains environment variables that are internal to the Python - If you use **PostgreSQL**: empty this field. Hyperion will fallback to PostgreSQL settings. 4. `USE_FACTORIES`: `True` by default, factories seed your database, if empty, with mocked data. - This is useful on SQLite to repopulate your new database after dropping the previous one. + This is useful on SQLite to repopulate your new database after dropping the previous one, of to create automatically your own user with admin privileges (see `FACTORIES_DEMO_USERS` below). +5. `FACTORIES_DEMO_USERS`: **Replace the first user's data with yours**. + These future users will be created automatically when launching Hyperion with an empty database. + Plus, your user will be there with your password and be admin out of the box. ## 5. Launch the API @@ -311,15 +318,21 @@ fastapi dev Check that your Hyperion instance is up and running by navigating to http://localhost:8000/information. -## 6. Create your own user +## 6. Create your own user (if not yet the case using factories) -There are many ways to do so, ranked here from easiest (GUI only) to hardest (CLI only). -Note that registration and activation are distinct steps, so for fun you may register one way and activate your account another way. +There are at least 5 distinct ways to do so outside the use of factories, ranked here from easiest (~GUI) to hardest (~CLI). + +> [!IMPORTANT] +> Using factories is the recommended way. +> All others methods are legacy and kept here for historical reasons. +> Feel free to create other users other ways for learning purposes. + +Note that registration and activation are distinct steps when calling calls to the API, so for fun you may register one way and activate your account another way (if you create your user directly in database, this distinction is not relevant).
-### With CalypSSO +### Using CalypSSO @@ -337,7 +350,7 @@ Open it and activate (end the creation of) your account.
-### With Titan +### Using Titan @@ -412,17 +425,54 @@ curl --json '{
-## 7. Make the first user admin +
+ + +### Using a database client in command line + + > [!WARNING] -> This may not work if you ran the factories +> Work in progress + +1. Open a shell connected to your database for Hyperion + - PostgreSQL: see above, generally `psql -U -d hyperion`. + - SQLite: ... +2. Insert your own user into the users' table (for `centrale_lyon` school, generate your own user UUID and salted hash, feel free to add insert values into nullable columns) : + +```sql +insert into core_user (id, firstname, name, nickname, email, password_hash, school_id, account_type) values ('01234567-89ab-cdef-0123-456789abcdef', '', '', '', '', '$2b$$', 'd9772da7-1142-4002-8b86-b694b431dfed', 'student'); +``` + +
+ +## 7. Make your user admin (if not yet the case using factories) + +> [!IMPORTANT] +> Again, using factories is the recommended way. + +### If there is exactly one user in the database -If there is exactly one user in the database, you can make it admin using the following command: +Then you can make it admin using the following command: ```bash curl -X POST http://localhost:8000/users/make-admin ``` +### Using a database client in command line + +> [!WARNING] +> Work in progress + +1. Open a shell connected to your database for Hyperion + - PostgreSQL: see above, generally `psql -U -d hyperion`. + - SQLite: ... +2. Get the UUID for your own user, then insert it and the UUID for the admin grouptype in the memberships table : + +```sql +insert into core_membership (user_id, group_id) values ('', '0a25cb76-4b63-4fd3-b939-da6d9feabf28'); +``` + ---
diff --git a/config.template.yaml b/config.template.yaml index 14cc889d6a..64c55b89d8 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -49,8 +49,6 @@ CLIENT_URL: http://127.0.0.1:8000/ # NOTE: A trailing / is required # - but the docker container should call http://host.docker.internal:8000/auth/token and not your localhost address #OVERRIDDEN_CLIENT_URL_FOR_OIDC: "http://host.docker.internal:8000/" # NOTE: A trailing / is required -# Configure AuthClients, to allow services to authenticate users using OAuth2 or Openid connect -# The following format should be used in yaml config files: # Origins for the CORS middleware. `["http://localhost:3000"]` can be used for development. # See https://fastapi.tiangolo.com/tutorial/cors/ # It should begin with 'http://' or 'https:// and should never end with a '/' @@ -58,6 +56,14 @@ CORS_ORIGINS: - "*" # For a local instance, using a wildcard "*" is convenient # - http://localhost:3000 # - http://127.0.0.1:3000 + +################ +# Auth Clients # +################ + +# Configure AuthClients, to allow services to authenticate users using OAuth2 or OpenID Connect +# The Python-expected type is `dict[str, AuthClientConfig]` where the class `AuthClientConfig` is from `app.core.utils.config`. +# Thus, the following format should be used in yaml config files: # ```yml # AUTH_CLIENTS: # : @@ -70,10 +76,12 @@ CORS_ORIGINS: # `AuthClientClassName` should be a class from `app.utils.auth.providers` AUTH_CLIENTS: Titan: - secret: + secret: null # PKCE redirect_uri: - http://localhost:3000/static.html - http://127.0.0.1:3000/static.html + - https://myecl.fr/static.html + - "fr.myecl.titan://authorized auth_client: AppAuthClient Postman: secret: PostmanSecret @@ -91,8 +99,48 @@ AUTH_CLIENTS: SQLITE_DB: app.db # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) DATABASE_DEBUG: False # If True, will print all SQL queries in the console LOG_DEBUG_MESSAGES: False -# if True and the database is empty, it will be seeded with mocked data -USE_FACTORIES: True +NB_WORKERS: 6 # Not yet used... + +############# +# Factories # +############# + +USE_FACTORIES: True # if True and the database is empty, it will be seeded with mocked data + +# Configure demo users, to populate the db with your users +# The Python-expected type is `list[UserDemoFactoryConfig]` where the class `UserDemoFactoryConfig` is from `app.core.utils.config`. +# Thus, the following format should be used in yaml config files: +# ```yml +# FACTORIES_DEMO_USERS +# - firstname: +# name: +# nickname: (or ) +# email: +# password: +# groups: +# - +# - +# ``` +# Group UUIDs should be values of the GroupType enum from `app.core.groups.groupe_type.GroupType` +FACTORIES_DEMO_USERS: + - firstname: Your Firstname + name: Your Name + nickname: Your Nickname + email: your-firstname.your-name@etu.ec-lyon.fr + password: Your_P@$$w0rd + groups: + - 0a25cb76-4b63-4fd3-b939-da6d9feabf28 # admin + - 45649735-866a-49df-b04b-a13c74fd5886 # AE + - 1f841bd9-00be-41a7-96e1-860a18a46105 # eclair + - firstname: Foucauld + name: Bellanger + nickname: Ñool + email: foucauld.bellanger@etu.ec-lyon.fr + password: azerty + groups: + - 1f841bd9-00be-41a7-96e1-860a18a46105 + - 45649735-866a-49df-b04b-a13c74fd5886 + - 4ec5ae77-f955-4309-96a5-19cc3c8be71c ##################################### # SMTP configuration using starttls # From 04f935a9062cebe10e0c89c452a5cec654e69c28 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 7 Oct 2025 02:13:25 +0200 Subject: [PATCH 26/42] Fix(HA): no error logs in dev when it's alright --- app/utils/state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/utils/state.py b/app/utils/state.py index c457e58e6c..0a31dde7fe 100644 --- a/app/utils/state.py +++ b/app/utils/state.py @@ -152,7 +152,7 @@ def init_payment_tools( hyperion_error_logger: logging.Logger, ) -> dict[HelloAssoConfigName, PaymentTool]: if settings.HELLOASSO_API_BASE is None: - hyperion_error_logger.error( + hyperion_error_logger.warning( "HelloAsso API base URL is not set in settings, payment won't be available", ) return {} From 75f4b87f0867a9694d330b036b57ace7b16b51aa Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Fri, 10 Oct 2025 08:30:20 +0200 Subject: [PATCH 27/42] rm useless gitguardian.yml, leave example credentials in clear --- .gitguardian.yaml | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 .gitguardian.yaml diff --git a/.gitguardian.yaml b/.gitguardian.yaml deleted file mode 100644 index 086ec06d51..0000000000 --- a/.gitguardian.yaml +++ /dev/null @@ -1,40 +0,0 @@ -version: 2 - -secret: - show_secrets: true # super annoying to find what is wrong otherwise - - ignored_paths: - - config.template.yaml - - ignored_matches: - - name: ACCESS_TOKEN_SECRET_KEY - match: cb1a54fe4af5b5d7d710946fe1ff3698a1e9ae14b964cb652eae52336b2ef5ac - - name: RSA_PRIVATE_PEM_STRING - match: | - -----BEGIN RSA PRIVATE KEY----- - MIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k - iClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN - x0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto - W9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR - 9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+ - VAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/ - kYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ - OKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L - H9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA - rro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh - Kui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF - vvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN - i0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE - xjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt - CHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h - DygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4 - EX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c - //Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC - kqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr - kQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2 - 6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA - 0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi - 1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb - nADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32 - 8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= - -----END RSA PRIVATE KEY----- From e3e4063bea8d8fd5ef25f26a2bfafeec5fb9ab68 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Fri, 10 Oct 2025 08:52:55 +0200 Subject: [PATCH 28/42] Fix: test config --- tests/.env.test | 16 +++ tests/config.test.yaml | 262 ++++++++++++++++++++++++++++++++++------- 2 files changed, 238 insertions(+), 40 deletions(-) diff --git a/tests/.env.test b/tests/.env.test index 7ee75aadec..f6090c0e0e 100644 --- a/tests/.env.test +++ b/tests/.env.test @@ -2,16 +2,32 @@ # This dotenv file and its values should NEVER be used in PRODUCTION! # ########################################################################### +############################ +# PostgreSQL configuration # +############################ + # Will be used if tests are run with postgresql (should be the case because postgres is used in production) +# Should be set to the name of the postgres container POSTGRES_HOST="localhost" POSTGRES_USER="hyperion" POSTGRES_PASSWORD="somerealpassword" POSTGRES_DB="hyperion" POSTGRES_TZ="Etc/UTC" +######################## # Redis configuration # +######################## +# Redis configuration is needed to use the rate limiter, or multiple uvicorn workers +# We use the default redis configuration, so the protected mode is enabled by default (see https://redis.io/docs/manual/security/#protected-mode) +# If you want to use a custom configuration, a password and a specific binds should be used to avoid security issues + +# REDIS_HOST may be commented to disable Redis during development if you don't have a redis server running, in production it should be set to the name of the redis container REDIS_HOST="localhost" REDIS_PORT=6379 +# Should be commented during development to work with docker-compose-dev, and set in production #REDIS_PASSWORD="" REDIS_LIMIT=5 REDIS_WINDOW=60 + + + diff --git a/tests/config.test.yaml b/tests/config.test.yaml index 96f57d714d..7a2544c4d3 100644 --- a/tests/config.test.yaml +++ b/tests/config.test.yaml @@ -2,65 +2,174 @@ # This dotenv file and its values should NEVER be used in PRODUCTION! # ########################################################################### -# SQLITE_DB: "test.db" # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (should not be used if possible) +############################################### +# Authorization using OAuth or Openid connect # +############################################### -# Authorization using JWT # +# ACCESS_TOKEN_SECRET_KEY should contain a random string with enough entropy (at least 32 bytes long) to securely sign all access_tokens for OAuth and Openid connect +# If you want to generate a 2048-bit long PEM certificate and save it in a file, the following command may be used: +# openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem ACCESS_TOKEN_SECRET_KEY: "YWZOHliiI53lJMJc5BI_WbGbA4GF2T7Wbt1airIhOXEa3c021c4-1c55-4182-b141-7778bcc8fac4" # Note: modifing this token requires to update the common `test_check_settings_mocking` test -RSA_PRIVATE_PEM_STRING: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k\niClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN\nx0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto\nW9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR\n9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+\nVAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/\nkYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ\nOKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L\nH9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA\nrro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh\nKui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF\nvvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN\ni0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE\nxjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt\nCHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h\nDygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4\nEX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c\n//Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC\nkqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr\nkQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2\n6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA\n0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi\n1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb\nnADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32\n8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw=\n-----END RSA PRIVATE KEY-----\n" -# Host or url of the API, used for Openid connect discovery endpoint -# NOTE: A trailing / is required -CLIENT_URL: "http://127.0.0.1:8000/" +# RSA_PRIVATE_PEM_STRING should be a string containing the PEM certificate of a private RSA key. It will be used to sign id_tokens for Openid connect authentication +# The example below was generated using a 2048-bit RSA key generator +RSA_PRIVATE_PEM_STRING: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k + iClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN + x0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto + W9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR + 9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+ + VAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/ + kYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ + OKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L + H9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA + rro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh + Kui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF + vvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN + i0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE + xjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt + CHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h + DygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4 + EX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c + //Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC + kqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr + kQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2 + 6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA + 0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi + 1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb + nADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32 + 8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= + -----END RSA PRIVATE KEY----- +# Host or URL of the instance of Hyperion +# This url will be especially used for OIDC/OAuth2 discovery endpoint and links send by email +CLIENT_URL: http://127.0.0.1:8000/ # NOTE: A trailing / is required + +# Sometimes, when running third services with oidc inside Docker containers, and running Hyperion on your local device +# you may need to use a different url for call made from docker and call made from your device +# For exemple: +# - you will access the login page from your browser http://localhost:8000/auth/authorize +# - but the docker container should call http://host.docker.internal:8000/auth/token and not your localhost address +#OVERRIDDEN_CLIENT_URL_FOR_OIDC: "http://host.docker.internal:8000/" # NOTE: A trailing / is required + +# Origins for the CORS middleware. `["http://localhost:3000"]` can be used for development. +# See https://fastapi.tiangolo.com/tutorial/cors/ +# It should begin with 'http://' or 'https:// and should never end with a '/' +CORS_ORIGINS: + - https://test-authorized-origin.com +# - "*" # For a local instance, using a wildcard "*" is convenient +# - http://localhost:3000 +# - http://127.0.0.1:3000 + +################ +# Auth Clients # +################ + +# Configure AuthClients, to allow services to authenticate users using OAuth2 or OpenID Connect +# The Python-expected type is `dict[str, AuthClientConfig]` where the class `AuthClientConfig` is from `app.core.utils.config`. +# Thus, the following format should be used in yaml config files: +# ```yml +# AUTH_CLIENTS: +# : +# secret: (or to use PKCE instead of a client secret) +# redirect_uri: +# - +# - +# auth_client: +# ``` +# `AuthClientClassName` should be a class from `app.utils.auth.providers` AUTH_CLIENTS: AppAuthClientWithPKCE: + secret: null redirect_uri: - - "http://127.0.0.1:8000/docs" - auth_client: "AppAuthClient" + - http://127.0.0.1:8000/docs + auth_client: AppAuthClient AppAuthClientWithClientSecret: - secret: "secret" + secret: secret redirect_uri: - - "http://127.0.0.1:8000/docs" + - http://127.0.0.1:8000/docs auth_client: "AppAuthClient" BaseAuthClient: - secret: "secret" + secret: secret redirect_uri: - - "http://127.0.0.1:8000/docs" - auth_client: "BaseAuthClient" + - http://127.0.0.1:8000/docs + auth_client: BaseAuthClient RalllyAuthClient: - secret: "secret" + secret: secret redirect_uri: - - "http://127.0.0.1:8000/docs" - auth_client: "RalllyAuthClient" + - http://127.0.0.1:8000/docs + auth_client: RalllyAuthClient SynapseAuthClient: - secret: "secret" + secret: secret redirect_uri: - - "http://127.0.0.1:8000/docs" - auth_client: "SynapseAuthClient" + - http://127.0.0.1:8000/docs + auth_client: SynapseAuthClient AcceptingOnlyECLUsersAuthClient: - secret: "secret" + secret: secret redirect_uri: - - "http://127.0.0.1:8000/docs" - auth_client: "NextcloudAuthClient" + - http://127.0.0.1:8000/docs + auth_client: NextcloudAuthClient RestrictingUsersGroupsAuthClient: - secret: "secret" + secret: secret redirect_uri: - - "http://127.0.0.1:8000/docs" - auth_client: "DocumensoAuthClient" + - http://127.0.0.1:8000/docs + auth_client: DocumensoAuthClient -# Logging configuration # +##################### +# Hyperion settings # +##################### -LOG_DEBUG_MESSAGES: true -ENABLE_RATE_LIMITER: false +#SQLITE_DB: app.db # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) +DATABASE_DEBUG: False # If True, will print all SQL queries in the console +LOG_DEBUG_MESSAGES: True +NB_WORKERS: 6 # Not yet used... -# CORS_ORIGINS should be a list of urls allowed to make requests to the API -# It should begin with 'http://' or 'https:// and should never end with a '/' -CORS_ORIGINS: ["https://test-authorized-origin.com"] +############# +# Factories # +############# + +USE_FACTORIES: True # if True and the database is empty, it will be seeded with mocked data -# If True, will print all SQL queries in the console -DATABASE_DEBUG: False +# Configure demo users, to populate the db with your users +# The Python-expected type is `list[UserDemoFactoryConfig]` where the class `UserDemoFactoryConfig` is from `app.core.utils.config`. +# Thus, the following format should be used in yaml config files: +# ```yml +# FACTORIES_DEMO_USERS +# - firstname: +# name: +# nickname: (or ) +# email: +# password: +# groups: +# - +# - +# ``` +# Group UUIDs should be values of the GroupType enum from `app.core.groups.groupe_type.GroupType` +FACTORIES_DEMO_USERS: + - firstname: Your Firstname + name: Your Name + nickname: Your Nickname + email: your-firstname.your-name@etu.ec-lyon.fr + password: Your_P@$$w0rd + groups: + - 0a25cb76-4b63-4fd3-b939-da6d9feabf28 # admin + - 45649735-866a-49df-b04b-a13c74fd5886 # AE + - 1f841bd9-00be-41a7-96e1-860a18a46105 # eclair + - firstname: Foucauld + name: Bellanger + nickname: Ñool + email: foucauld.bellanger@etu.ec-lyon.fr + password: azerty + groups: + - 1f841bd9-00be-41a7-96e1-860a18a46105 + - 45649735-866a-49df-b04b-a13c74fd5886 + - 4ec5ae77-f955-4309-96a5-19cc3c8be71c +##################################### # SMTP configuration using starttls # +##################################### + SMTP_ACTIVE: False SMTP_PORT: 587 SMTP_SERVER: "" @@ -68,14 +177,87 @@ SMTP_USERNAME: "" SMTP_PASSWORD: "" SMTP_EMAIL: "" -# Push notifications using Firebase Cloud Messaging -USE_FIREBASE: false +########################## +# Firebase Configuration # +########################## + +# To enable Firebase push notification capabilities, a JSON key file named `firebase.json` should be placed at Hyperion root. +# This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. +USE_FIREBASE: False + +######################## +# Matrix configuration # +######################## + +# Matrix configuration is optional. If configured, Hyperion will be able to send messages to a Matrix server. +# This configuration will be used to send errors messages. +# If the following parameters are not set, logging won't use the Matrix handler +# MATRIX_SERVER_BASE_URL is optional, the official Matrix server will be used if not configured +# Advanced note: Username and password will be used to ask for an access token. A Matrix custom client `Hyperion` is used to make all requests +#MATRIX_SERVER_BASE_URL: "https://matrix.example.org/" +#MATRIX_TOKEN: "mct_..." +#MATRIX_LOG_ERROR_ROOM_ID: "!...:myecl.fr" +#MATRIX_LOG_AMAP_ROOM_ID: "" + +############################# +# Token to use the TMDB API # +############################# + +# This API key is required in order to send requests to the Internet Movie Database. +# It is only used in the Cinema module. +#THE_MOVIE_DB_API: "" + +#################### +# S3 configuration # +#################### + +# S3 configuration is needed to use the S3 storage for MyECLPay logs + +#S3_BUCKET_NAME: "" +#S3_ACCESS_KEY_ID: "" +#S3_SECRET_ACCESS_KEY: "" + +############## +# Google API # +############## + +# Google API configuration # +# Google API is used to upload files to Google Drive +# See ./app/utils/google_api/README.md for more information +#GOOGLE_API_CLIENT_ID: "" +#GOOGLE_API_CLIENT_SECRET: "" + +#RAID_DRIVE_REFRESH_TOKEN: "" +#RAID_DRIVE_API_KEY: "" +#RAID_DRIVE_CLIENT_ID: "" +#RAID_DRIVE_CLIENT_SECRET: "" +#RAID_PAYMENT_REDIRECTION_URL: "" + +########################### +# HelloAsso configuration # +########################### -# Payment configuration # +# To be able to use payment features using HelloAsso, you need to set a client id, secret for their API +# HelloAsso provide a sandbox to be able to realize tests +# HELLOASSO_API_BASE should have the format: `api.helloasso-sandbox.com` +# HelloAsso only allow 20 simultaneous active access token. Note that each Hyperion worker will need its own access token. -TRUSTED_PAYMENT_REDIRECT_URLS: ["http://localhost:3000/payment_callback"] +HELLOASSO_CONFIGURATIONS: # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] +# MYECLPAY: +# helloasso_client_id: ... +# helloasso_client_secret: ... +# helloasso_slug: "AEECL" +# redirection_uri: null +HELLOASSO_API_BASE: api.helloasso-sandbox.com -HELLOASSO_API_BASE: "https://api.helloasso.com/v3" -HELLOASSO_CONFIGURATIONS: {} +# Maximum wallet balance for MyECLPay in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value +MYECLPAY_MAXIMUM_WALLET_BALANCE: 8000 -MYECLPAY_MAXIMUM_WALLET_BALANCE: 5000 +# Trusted urls is a list of redirect payment url that can be trusted by Hyperion. +# These urls will be used to validate the redirect url provided by the front +TRUSTED_PAYMENT_REDIRECT_URLS: + - http://localhost:3000/payment_callback +# MyECLPay requires an external service to recurrently check for transactions and state integrity, this service needs an access to all the data related to the transactions and the users involved +# This service will use a special token to access the data +# If this token is not set, the service will not be able to access the data and no integrity check will be performed +#MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN: "" From be1433b250bdc090142baa1b6af3145ae36e157e Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Fri, 10 Oct 2025 09:33:27 +0200 Subject: [PATCH 29/42] Fix test YAML config --- tests/config.test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/config.test.yaml b/tests/config.test.yaml index 7a2544c4d3..f27667aefd 100644 --- a/tests/config.test.yaml +++ b/tests/config.test.yaml @@ -242,7 +242,7 @@ USE_FIREBASE: False # HELLOASSO_API_BASE should have the format: `api.helloasso-sandbox.com` # HelloAsso only allow 20 simultaneous active access token. Note that each Hyperion worker will need its own access token. -HELLOASSO_CONFIGURATIONS: # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] +#HELLOASSO_CONFIGURATIONS: # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] # MYECLPAY: # helloasso_client_id: ... # helloasso_client_secret: ... From c2217f73ef8069015281b2c8163808f567cb1a18 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Fri, 10 Oct 2025 09:39:19 +0200 Subject: [PATCH 30/42] Failing tests: try previous psycopg minor --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 1644e377eb..f259bde560 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -18,7 +18,7 @@ jellyfish==1.0.4 # String Matching Jinja2==3.1.6 # template engine for html files phonenumbers==8.13.43 # Used for phone number validation psutil==7.0.0 # psutil is used to determine the number of Hyperion workers -psycopg[binary]==3.2.10 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) +psycopg[binary]==3.1.20 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) pydantic-settings==2.3.4 pydantic==2.7.4 pyjwt[crypto]==2.8.0 # generate and verify the JWT tokens, imported as `jwt` From 8814f13e9ac09b9dd0a9d4af0acbc245e5241936 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Fri, 10 Oct 2025 09:59:29 +0200 Subject: [PATCH 31/42] Fix: rm factories from tests --- requirements-common.txt | 2 +- tests/.env.test | 3 -- tests/config.test.yaml | 92 +---------------------------------------- 3 files changed, 2 insertions(+), 95 deletions(-) diff --git a/requirements-common.txt b/requirements-common.txt index f259bde560..1644e377eb 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -18,7 +18,7 @@ jellyfish==1.0.4 # String Matching Jinja2==3.1.6 # template engine for html files phonenumbers==8.13.43 # Used for phone number validation psutil==7.0.0 # psutil is used to determine the number of Hyperion workers -psycopg[binary]==3.1.20 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) +psycopg[binary]==3.2.10 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) pydantic-settings==2.3.4 pydantic==2.7.4 pyjwt[crypto]==2.8.0 # generate and verify the JWT tokens, imported as `jwt` diff --git a/tests/.env.test b/tests/.env.test index f6090c0e0e..376f866d2e 100644 --- a/tests/.env.test +++ b/tests/.env.test @@ -28,6 +28,3 @@ REDIS_PORT=6379 #REDIS_PASSWORD="" REDIS_LIMIT=5 REDIS_WINDOW=60 - - - diff --git a/tests/config.test.yaml b/tests/config.test.yaml index f27667aefd..8fa6f7a21f 100644 --- a/tests/config.test.yaml +++ b/tests/config.test.yaml @@ -123,48 +123,6 @@ AUTH_CLIENTS: #SQLITE_DB: app.db # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) DATABASE_DEBUG: False # If True, will print all SQL queries in the console LOG_DEBUG_MESSAGES: True -NB_WORKERS: 6 # Not yet used... - -############# -# Factories # -############# - -USE_FACTORIES: True # if True and the database is empty, it will be seeded with mocked data - -# Configure demo users, to populate the db with your users -# The Python-expected type is `list[UserDemoFactoryConfig]` where the class `UserDemoFactoryConfig` is from `app.core.utils.config`. -# Thus, the following format should be used in yaml config files: -# ```yml -# FACTORIES_DEMO_USERS -# - firstname: -# name: -# nickname: (or ) -# email: -# password: -# groups: -# - -# - -# ``` -# Group UUIDs should be values of the GroupType enum from `app.core.groups.groupe_type.GroupType` -FACTORIES_DEMO_USERS: - - firstname: Your Firstname - name: Your Name - nickname: Your Nickname - email: your-firstname.your-name@etu.ec-lyon.fr - password: Your_P@$$w0rd - groups: - - 0a25cb76-4b63-4fd3-b939-da6d9feabf28 # admin - - 45649735-866a-49df-b04b-a13c74fd5886 # AE - - 1f841bd9-00be-41a7-96e1-860a18a46105 # eclair - - firstname: Foucauld - name: Bellanger - nickname: Ñool - email: foucauld.bellanger@etu.ec-lyon.fr - password: azerty - groups: - - 1f841bd9-00be-41a7-96e1-860a18a46105 - - 45649735-866a-49df-b04b-a13c74fd5886 - - 4ec5ae77-f955-4309-96a5-19cc3c8be71c ##################################### # SMTP configuration using starttls # @@ -185,54 +143,6 @@ SMTP_EMAIL: "" # This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. USE_FIREBASE: False -######################## -# Matrix configuration # -######################## - -# Matrix configuration is optional. If configured, Hyperion will be able to send messages to a Matrix server. -# This configuration will be used to send errors messages. -# If the following parameters are not set, logging won't use the Matrix handler -# MATRIX_SERVER_BASE_URL is optional, the official Matrix server will be used if not configured -# Advanced note: Username and password will be used to ask for an access token. A Matrix custom client `Hyperion` is used to make all requests -#MATRIX_SERVER_BASE_URL: "https://matrix.example.org/" -#MATRIX_TOKEN: "mct_..." -#MATRIX_LOG_ERROR_ROOM_ID: "!...:myecl.fr" -#MATRIX_LOG_AMAP_ROOM_ID: "" - -############################# -# Token to use the TMDB API # -############################# - -# This API key is required in order to send requests to the Internet Movie Database. -# It is only used in the Cinema module. -#THE_MOVIE_DB_API: "" - -#################### -# S3 configuration # -#################### - -# S3 configuration is needed to use the S3 storage for MyECLPay logs - -#S3_BUCKET_NAME: "" -#S3_ACCESS_KEY_ID: "" -#S3_SECRET_ACCESS_KEY: "" - -############## -# Google API # -############## - -# Google API configuration # -# Google API is used to upload files to Google Drive -# See ./app/utils/google_api/README.md for more information -#GOOGLE_API_CLIENT_ID: "" -#GOOGLE_API_CLIENT_SECRET: "" - -#RAID_DRIVE_REFRESH_TOKEN: "" -#RAID_DRIVE_API_KEY: "" -#RAID_DRIVE_CLIENT_ID: "" -#RAID_DRIVE_CLIENT_SECRET: "" -#RAID_PAYMENT_REDIRECTION_URL: "" - ########################### # HelloAsso configuration # ########################### @@ -242,7 +152,7 @@ USE_FIREBASE: False # HELLOASSO_API_BASE should have the format: `api.helloasso-sandbox.com` # HelloAsso only allow 20 simultaneous active access token. Note that each Hyperion worker will need its own access token. -#HELLOASSO_CONFIGURATIONS: # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] +HELLOASSO_CONFIGURATIONS: {} # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] # MYECLPAY: # helloasso_client_id: ... # helloasso_client_secret: ... From 25e52ef5ad2bc94644dcc12128826209f0606af9 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Fri, 10 Oct 2025 16:58:47 +0200 Subject: [PATCH 32/42] hopelessness --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ee51c2eff5..3b7158e5d6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: - 6379:6379 postgres: # Docker Hub image - image: postgres + image: "postgres:15.1" # Provide the password for postgres env: POSTGRES_PASSWORD: "somerealpassword" From 948a8efd834c7ac8fcd93cacc0e88747a4d46de0 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Mon, 13 Oct 2025 09:50:06 +0200 Subject: [PATCH 33/42] Fixes for test workflows and db --- .github/workflows/test.yml | 2 +- requirements-common.txt | 2 +- tests/config.test.yaml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3b7158e5d6..0fce09ddc3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,7 +57,7 @@ jobs: uses: actions/setup-python@v5 id: setup-python with: - python-version: "3.11" + python-version: "3.12" - name: Cache uv folder id: cache-uv diff --git a/requirements-common.txt b/requirements-common.txt index 1644e377eb..ad31100aa1 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -18,7 +18,7 @@ jellyfish==1.0.4 # String Matching Jinja2==3.1.6 # template engine for html files phonenumbers==8.13.43 # Used for phone number validation psutil==7.0.0 # psutil is used to determine the number of Hyperion workers -psycopg[binary]==3.2.10 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) +psycopg[binary]==3.2.9 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) pydantic-settings==2.3.4 pydantic==2.7.4 pyjwt[crypto]==2.8.0 # generate and verify the JWT tokens, imported as `jwt` diff --git a/tests/config.test.yaml b/tests/config.test.yaml index 8fa6f7a21f..0bc8ea447b 100644 --- a/tests/config.test.yaml +++ b/tests/config.test.yaml @@ -123,6 +123,7 @@ AUTH_CLIENTS: #SQLITE_DB: app.db # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) DATABASE_DEBUG: False # If True, will print all SQL queries in the console LOG_DEBUG_MESSAGES: True +ENABLE_RATE_LIMITER: False ##################################### # SMTP configuration using starttls # From ce00e0522e226b6bf55bb6f7704831137a77df15 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 14 Oct 2025 13:42:11 +0200 Subject: [PATCH 34/42] Minor fixes --- README.md | 4 ++-- config.template.yaml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6d1f8d6576..9bc6f44332 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ Check this file to know what can and should be set using these two files. ### The `.env` file -The `.env` contains environment variables which need to be accessed by the OS or by other services, such as the database. +The `.env` contains environment variables which can to be accessed by the OS or by other services, such as the database. #### With SQLite @@ -324,7 +324,7 @@ There are at least 5 distinct ways to do so outside the use of factories, ranked > [!IMPORTANT] > Using factories is the recommended way. -> All others methods are legacy and kept here for historical reasons. +> All others methods are legacy and kept here for historical reasons (excepted using Titan, which is the way users create their account in production). > Feel free to create other users other ways for learning purposes. Note that registration and activation are distinct steps when calling calls to the API, so for fun you may register one way and activate your account another way (if you create your user directly in database, this distinction is not relevant). diff --git a/config.template.yaml b/config.template.yaml index 64c55b89d8..8710719fad 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -99,7 +99,6 @@ AUTH_CLIENTS: SQLITE_DB: app.db # If set, the application use a SQLite database instead of PostgreSQL, for testing or development purposes (if possible PostgreSQL should be used instead) DATABASE_DEBUG: False # If True, will print all SQL queries in the console LOG_DEBUG_MESSAGES: False -NB_WORKERS: 6 # Not yet used... ############# # Factories # From 4bb9133ddc8ba73e4d10c48f45d70cc284488ac7 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 14 Oct 2025 16:23:05 +0200 Subject: [PATCH 35/42] Minor fixes --- README.md | 8 +++---- config.template.yaml | 51 ++++++++++++++++++++++---------------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 9bc6f44332..90a2308c9e 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ pyenv activate hyperion ### About Jellyfish and Rust -If you don't have Rust installed or don't want to install it, decrase the version of `jellyfish` to `0.10.0` in the `requirements-common.txt` file: +If you don't have Rust installed or don't want to install it, decrease the version of `jellyfish` to `0.10.0` in the `requirements-common.txt` file: ``` jellyfish==0.10.0 # String Matching @@ -282,10 +282,8 @@ POSTGRES_DB="hyperion" The `config.yaml` contains environment variables that are internal to the Python runtime _because_ they are only used in the Python code. -1. `ACCESS_TOKEN_SECRET_KEY`: **Uncomment it**. - You can generate your own if you want, or just change a couple characters, or leave it as it is. -2. `RSA_PRIVATE_PEM_STRING`: **Uncomment it**. - You can generate your own if you want, or just change a couple characters, or leave it as it is. +1. `ACCESS_TOKEN_SECRET_KEY`: You can generate your own if you want, or just change a couple characters, or leave it as it is. +2. `RSA_PRIVATE_PEM_STRING`: You can generate your own if you want, or just change a couple characters, or leave it as it is. 3. `SQLITE_DB`: **tells Hyperion whether to use SQLite or PostgreSQL**. - If you use **SQLite**: this field should be a (relative) filename, by default we named it `app.db`, you can change this name. Hyperion will create this file for you and use it as the database. diff --git a/config.template.yaml b/config.template.yaml index 8710719fad..e65ecd9d02 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -47,7 +47,7 @@ CLIENT_URL: http://127.0.0.1:8000/ # NOTE: A trailing / is required # For exemple: # - you will access the login page from your browser http://localhost:8000/auth/authorize # - but the docker container should call http://host.docker.internal:8000/auth/token and not your localhost address -#OVERRIDDEN_CLIENT_URL_FOR_OIDC: "http://host.docker.internal:8000/" # NOTE: A trailing / is required +#OVERRIDDEN_CLIENT_URL_FOR_OIDC: http://host.docker.internal:8000/ # NOTE: A trailing / is required # Origins for the CORS middleware. `["http://localhost:3000"]` can be used for development. # See https://fastapi.tiangolo.com/tutorial/cors/ @@ -81,7 +81,7 @@ AUTH_CLIENTS: - http://localhost:3000/static.html - http://127.0.0.1:3000/static.html - https://myecl.fr/static.html - - "fr.myecl.titan://authorized + - fr.myecl.titan://authorized auth_client: AppAuthClient Postman: secret: PostmanSecret @@ -147,10 +147,10 @@ FACTORIES_DEMO_USERS: SMTP_ACTIVE: False SMTP_PORT: 587 -SMTP_SERVER: "" -SMTP_USERNAME: "" -SMTP_PASSWORD: "" -SMTP_EMAIL: "" +SMTP_SERVER: +SMTP_USERNAME: +SMTP_PASSWORD: +SMTP_EMAIL: ########################## # Firebase Configuration # @@ -159,7 +159,6 @@ SMTP_EMAIL: "" # To enable Firebase push notification capabilities, a JSON key file named `firebase.json` should be placed at Hyperion root. # This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. USE_FIREBASE: False - ######################## # Matrix configuration # ######################## @@ -169,10 +168,10 @@ USE_FIREBASE: False # If the following parameters are not set, logging won't use the Matrix handler # MATRIX_SERVER_BASE_URL is optional, the official Matrix server will be used if not configured # Advanced note: Username and password will be used to ask for an access token. A Matrix custom client `Hyperion` is used to make all requests -#MATRIX_SERVER_BASE_URL: "https://matrix.example.org/" -#MATRIX_TOKEN: "mct_..." -#MATRIX_LOG_ERROR_ROOM_ID: "!...:myecl.fr" -#MATRIX_LOG_AMAP_ROOM_ID: "" +#MATRIX_SERVER_BASE_URL: https://matrix.example.org/ +#MATRIX_TOKEN: mct_... +#MATRIX_LOG_ERROR_ROOM_ID: !...:myecl.fr +#MATRIX_LOG_AMAP_ROOM_ID: ############################# # Token to use the TMDB API # @@ -180,7 +179,7 @@ USE_FIREBASE: False # This API key is required in order to send requests to the Internet Movie Database. # It is only used in the Cinema module. -#THE_MOVIE_DB_API: "" +#THE_MOVIE_DB_API: #################### # S3 configuration # @@ -188,9 +187,9 @@ USE_FIREBASE: False # S3 configuration is needed to use the S3 storage for MyECLPay logs -#S3_BUCKET_NAME: "" -#S3_ACCESS_KEY_ID: "" -#S3_SECRET_ACCESS_KEY: "" +#S3_BUCKET_NAME: +#S3_ACCESS_KEY_ID: +#S3_SECRET_ACCESS_KEY: ############## # Google API # @@ -199,14 +198,14 @@ USE_FIREBASE: False # Google API configuration # # Google API is used to upload files to Google Drive # See ./app/utils/google_api/README.md for more information -#GOOGLE_API_CLIENT_ID: "" -#GOOGLE_API_CLIENT_SECRET: "" +#GOOGLE_API_CLIENT_ID: +#GOOGLE_API_CLIENT_SECRET: -#RAID_DRIVE_REFRESH_TOKEN: "" -#RAID_DRIVE_API_KEY: "" -#RAID_DRIVE_CLIENT_ID: "" -#RAID_DRIVE_CLIENT_SECRET: "" -#RAID_PAYMENT_REDIRECTION_URL: "" +#RAID_DRIVE_REFRESH_TOKEN: +#RAID_DRIVE_API_KEY: +#RAID_DRIVE_CLIENT_ID: +#RAID_DRIVE_CLIENT_SECRET: +#RAID_PAYMENT_REDIRECTION_URL: ########################### # HelloAsso configuration # @@ -217,13 +216,13 @@ USE_FIREBASE: False # HELLOASSO_API_BASE should have the format: `api.helloasso-sandbox.com` # HelloAsso only allow 20 simultaneous active access token. Note that each Hyperion worker will need its own access token. -#HELLOASSO_CONFIGURATIONS: # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] +#HELLOASSO_CONFIGURATIONS: # MYECLPAY: # helloasso_client_id: ... # helloasso_client_secret: ... -# helloasso_slug: "AEECL" +# helloasso_slug: AEECL # redirection_uri: null -#HELLOASSO_API_BASE: "api.helloasso-sandbox.com" +#HELLOASSO_API_BASE: api.helloasso-sandbox.com # Maximum wallet balance for MyECLPay in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value #MYECLPAY_MAXIMUM_WALLET_BALANCE: 8000 @@ -236,4 +235,4 @@ USE_FIREBASE: False # MyECLPay requires an external service to recurrently check for transactions and state integrity, this service needs an access to all the data related to the transactions and the users involved # This service will use a special token to access the data # If this token is not set, the service will not be able to access the data and no integrity check will be performed -#MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN: "" +#MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN: From fa25af8b561b1818e5f1bf037636cefb04e53813 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 14 Oct 2025 16:31:14 +0200 Subject: [PATCH 36/42] small rewording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 90a2308c9e..53bbc07701 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ Check this file to know what can and should be set using these two files. ### The `.env` file -The `.env` contains environment variables which can to be accessed by the OS or by other services, such as the database. +The `.env` contains environment variables which can be accessed by the OS to convey them to other services that need them, such as the database. #### With SQLite From 3874df649620bf7a2d691423523173ce7789f6a3 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 14 Oct 2025 16:42:16 +0200 Subject: [PATCH 37/42] Put back `requests` and synchronous Matrix logging --- app/core/utils/log.py | 3 --- app/utils/communication/matrix.py | 15 ++++++--------- app/utils/loggers_tools/matrix_handler.py | 7 +------ requirements-common.txt | 1 + requirements-dev.txt | 1 + 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/app/core/utils/log.py b/app/core/utils/log.py index 02c5695201..f6fe2d68d8 100644 --- a/app/core/utils/log.py +++ b/app/core/utils/log.py @@ -7,7 +7,6 @@ from typing import Any import uvicorn -from fastapi import BackgroundTasks from app.core.utils.config import Settings @@ -122,7 +121,6 @@ def _get_config_dict(self, settings: Settings): # Send error to a Matrix server. If credentials are not set in settings, the handler will be disabled "formatter": "matrix", "class": "app.utils.loggers_tools.matrix_handler.MatrixHandler", - "background_tasks": BackgroundTasks, "room_id": settings.MATRIX_LOG_ERROR_ROOM_ID, "token": settings.MATRIX_TOKEN, "server_base_url": settings.MATRIX_SERVER_BASE_URL, @@ -135,7 +133,6 @@ def _get_config_dict(self, settings: Settings): # Send error to a Matrix server. If credentials are not set in settings, the handler will be disabled "formatter": "matrix", "class": "app.utils.loggers_tools.matrix_handler.MatrixHandler", - "background_tasks": BackgroundTasks, "room_id": settings.MATRIX_LOG_AMAP_ROOM_ID, "token": settings.MATRIX_TOKEN, "server_base_url": settings.MATRIX_SERVER_BASE_URL, diff --git a/app/utils/communication/matrix.py b/app/utils/communication/matrix.py index f50b827c61..566689fea8 100644 --- a/app/utils/communication/matrix.py +++ b/app/utils/communication/matrix.py @@ -1,6 +1,6 @@ from typing import Any -import httpx +import requests from app.types.exceptions import MatrixRequestError, MatrixSendMessageError @@ -24,7 +24,7 @@ def __init__( self.access_token = token - async def post( + def post( self, url: str, json: dict[str, Any], @@ -43,18 +43,15 @@ async def post( if "Authorization" not in headers: headers["Authorization"] = "Bearer " + self.access_token + response = requests.post(url, json=json, headers=headers, timeout=10) try: - async with httpx.AsyncClient() as client: - response = await client.post( - url, json=json, headers=headers, timeout=10 - ) response.raise_for_status() - except httpx.RequestError as err: + except requests.exceptions.HTTPError as err: raise MatrixRequestError() from err return response.json() - async def send_message(self, room_id: str, formatted_body: str) -> None: + def send_message(self, room_id: str, formatted_body: str) -> None: """ Send a message to the room `room_id`. `formatted_body` can contain html formatted text @@ -74,6 +71,6 @@ async def send_message(self, room_id: str, formatted_body: str) -> None: } try: - await self.post(url, json=data, headers=None) + self.post(url, json=data, headers=None) except MatrixRequestError as error: raise MatrixSendMessageError(room_id=room_id) from error diff --git a/app/utils/loggers_tools/matrix_handler.py b/app/utils/loggers_tools/matrix_handler.py index 15c5e810d0..3c09696a1a 100644 --- a/app/utils/loggers_tools/matrix_handler.py +++ b/app/utils/loggers_tools/matrix_handler.py @@ -1,7 +1,6 @@ import logging from logging import StreamHandler -from fastapi import BackgroundTasks from typing_extensions import override from app.utils.communication.matrix import Matrix @@ -22,7 +21,6 @@ class MatrixHandler(StreamHandler): def __init__( self, - background_tasks: BackgroundTasks, room_id: str, token: str, server_base_url: str | None, @@ -32,7 +30,6 @@ def __init__( super().__init__() self.setLevel(level) - self.background_tasks = background_tasks self.room_id = room_id self.enabled = enabled if self.enabled: @@ -46,9 +43,7 @@ def emit(self, record): if self.enabled: msg = self.format(record) try: - self.background_tasks.add_task( - self.matrix.send_message, room_id=self.room_id, formatted_body=msg - ) + self.matrix.send_message(self.room_id, msg) # We should catch and log any error, as Python may discarded them in production except Exception as err: # We use warning level so that the message is not sent to matrix again diff --git a/requirements-common.txt b/requirements-common.txt index ad31100aa1..e67d7860e2 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -26,6 +26,7 @@ PyMuPDF==1.24.9 # PDF processing, imported as `fitz` pypdf==4.3.1 python-multipart==0.0.18 # a form data parser, as oauth flow requires form-data parameters redis==5.0.8 +requests==2.32.4 sqlalchemy-utils == 0.41.2 SQLAlchemy[asyncio]==2.0.32 # [asyncio] allows greenlet to be installed on Apple M1 devices. unidecode==1.3.8 diff --git a/requirements-dev.txt b/requirements-dev.txt index c21a3be872..c949a25188 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,3 +14,4 @@ types-Authlib==1.5.0.20250516 types-fpdf2==2.8.3.20250516 types-psutil==7.0.0.20250601 types-redis==4.6.0.20241004 +types-requests==2.32.0.20250515 From 4c486c5d03b70ac29fa5dab8da55d6d5753745c9 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 14 Oct 2025 17:34:17 +0200 Subject: [PATCH 38/42] Fix ruff: TCH was renamed TC in 0.8 --- app/utils/loggers_tools/matrix_handler.py | 3 +-- app/utils/loggers_tools/s3_handler.py | 3 +-- pyproject.toml | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/utils/loggers_tools/matrix_handler.py b/app/utils/loggers_tools/matrix_handler.py index 3c09696a1a..d95a2b6ae1 100644 --- a/app/utils/loggers_tools/matrix_handler.py +++ b/app/utils/loggers_tools/matrix_handler.py @@ -1,7 +1,6 @@ import logging from logging import StreamHandler - -from typing_extensions import override +from typing import override from app.utils.communication.matrix import Matrix diff --git a/app/utils/loggers_tools/s3_handler.py b/app/utils/loggers_tools/s3_handler.py index 3aa0c6ed90..a64b0f0825 100644 --- a/app/utils/loggers_tools/s3_handler.py +++ b/app/utils/loggers_tools/s3_handler.py @@ -1,8 +1,7 @@ import string from datetime import UTC, datetime from logging import StreamHandler - -from typing_extensions import override +from typing import override from app.types.s3_access import S3Access from app.utils.tools import get_random_string diff --git a/pyproject.toml b/pyproject.toml index 9a8b75eb08..b9668634eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,9 +25,9 @@ minimal-titan-version-code = 139 # Same as Black. line-length = 88 indent-width = 4 -target-version = "py311" +target-version = "py312" -[tool.lint] +[tool.ruff.lint] select = [ "FAST", "YTT", @@ -70,7 +70,7 @@ select = [ "FURB", "RUF", "TRY", - "TCH", + "TC", ] # We may want to enable "ERA" to found commented-out code ignore = [ @@ -98,7 +98,7 @@ ignore = [ fixable = ["ALL"] unfixable = [] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] # Allow `assert` and hardcoded passwords for tests. # Ignore PLW0603 to be able to define global models from init fixture "tests/*" = ["S101", "S105", "S106", "ASYNC230", "PLW0603"] @@ -115,7 +115,7 @@ unfixable = [] # Allow complexe methods for auth endpoints "app/core/auth/endpoints_auth.py" = ["C901"] -[tool.ruff.mccabe] +[tool.ruff.lint.mccabe] # Flag errors (`C901`) whenever the complexity level exceeds 18. max-complexity = 18 From 2bbfe2c6a79b009f39a4b64e43e3c86563e1ff0c Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Tue, 14 Oct 2025 23:33:42 +0200 Subject: [PATCH 39/42] Fix mypy too --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b9668634eb..cf213383a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -130,7 +130,7 @@ skip-magic-trailing-comma = false line-ending = "auto" [tool.mypy] -python_version = "3.11" +python_version = "3.12" plugins = ["pydantic.mypy"] warn_unreachable = true From f819dfbefb94c4203a0733cf0a0ed5f21aec59c4 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 19 Oct 2025 11:06:42 +0200 Subject: [PATCH 40/42] Numerous fixes due to the comments --- README.md | 11 +++--- config.template.yaml | 82 ++++++++++++++++++++------------------------ 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 53bbc07701..3519ca3b7a 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,7 @@ While with Docker you should have rather something like: ```sh POSTGRES_USER="hyperion" POSTGRES_PASSWORD="" +# POSTGRES_HOST Should be set to the name of the postgres container POSTGRES_HOST="hyperion-db" POSTGRES_DB="hyperion" ``` @@ -282,17 +283,17 @@ POSTGRES_DB="hyperion" The `config.yaml` contains environment variables that are internal to the Python runtime _because_ they are only used in the Python code. -1. `ACCESS_TOKEN_SECRET_KEY`: You can generate your own if you want, or just change a couple characters, or leave it as it is. -2. `RSA_PRIVATE_PEM_STRING`: You can generate your own if you want, or just change a couple characters, or leave it as it is. -3. `SQLITE_DB`: **tells Hyperion whether to use SQLite or PostgreSQL**. +1. `ACCESS_TOKEN_SECRET_KEY` and `RSA_PRIVATE_PEM_STRING`: An example of each is provided. + You can generate your own if you want, or just change a couple characters in the examples, or deliberately leave it as it is. +2. `SQLITE_DB`: **tells Hyperion whether to use SQLite or PostgreSQL**. - If you use **SQLite**: this field should be a (relative) filename, by default we named it `app.db`, you can change this name. Hyperion will create this file for you and use it as the database. Any PostgreSQL-related configuration will be ignored. - If you use **PostgreSQL**: empty this field. Hyperion will fallback to PostgreSQL settings. -4. `USE_FACTORIES`: `True` by default, factories seed your database, if empty, with mocked data. +3. `USE_FACTORIES`: `True` by default, factories seed your database, if empty, with mocked data. This is useful on SQLite to repopulate your new database after dropping the previous one, of to create automatically your own user with admin privileges (see `FACTORIES_DEMO_USERS` below). -5. `FACTORIES_DEMO_USERS`: **Replace the first user's data with yours**. +4. `FACTORIES_DEMO_USERS`: **Replace the first user's data with yours**. These future users will be created automatically when launching Hyperion with an empty database. Plus, your user will be there with your password and be admin out of the box. diff --git a/config.template.yaml b/config.template.yaml index e65ecd9d02..73699fb80a 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -3,40 +3,40 @@ ############################################### # ACCESS_TOKEN_SECRET_KEY should contain a random string with enough entropy (at least 32 bytes long) to securely sign all access_tokens for OAuth and Openid connect -# If you want to generate a 2048-bit long PEM certificate and save it in a file, the following command may be used: -# openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem -ACCESS_TOKEN_SECRET_KEY: YWZOHliiI53lJMJc5BI_WbGbA4GF2T7Wbt1airIhOXEa3c021c4-1c55-4182-b141-7778bcc8fac4 +ACCESS_TOKEN_SECRET_KEY: #YWZOHliiI53lJMJc5BI_WbGbA4GF2T7Wbt1airIhOXEa3c021c4-1c55-4182-b141-7778bcc8fac4 # RSA_PRIVATE_PEM_STRING should be a string containing the PEM certificate of a private RSA key. It will be used to sign id_tokens for Openid connect authentication -# The example below was generated using a 2048-bit RSA key generator +# The 2048-bit-long PEM certificate example below was generated using a 2048-bit RSA key generator online. +# If you want to generate a PEM certificate and save in a file, the following openssl command may be used: +# openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem RSA_PRIVATE_PEM_STRING: | - -----BEGIN RSA PRIVATE KEY----- - MIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k - iClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN - x0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto - W9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR - 9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+ - VAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/ - kYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ - OKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L - H9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA - rro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh - Kui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF - vvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN - i0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE - xjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt - CHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h - DygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4 - EX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c - //Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC - kqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr - kQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2 - 6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA - 0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi - 1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb - nADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32 - 8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= - -----END RSA PRIVATE KEY----- + # -----BEGIN RSA PRIVATE KEY----- + # MIIEpQIBAAKCAQEA1tpj3TZDkJakp2RygsM392pQbcmNBOGFT8FlETcRG/JVFT7k + # iClJu+CVOJSVD0epfpYp93cYepfw74SezYnBCyuoLJ2yg5Qh4KlCrWmvwM7vhFIN + # x0xddIQi+Gm0T3dxGtv4Ga50TYX4SV4FE3ctJG9m3pyNF6POODp5tMJvShQWYTto + # W9qNhltZ8Z+14bq2INV/efpT47WuMT+VD/fa9/WwopAtgBcQOvq57fv5+DaPOIVR + # 9BiP7F+pv+v6wQ373hI22QzCMsA4Whl+BmWFKcFoBDOBRjlW5VqhJWJkWZIRP0q+ + # VAZHk2xJK+0YFc9jmaC+ExMtuyHYK0RnQK/8LQIDAQABAoIBABxJ8v4sZ+cAvrs/ + # kYhAFf1gpShfck7jNr9SknEa1Aje9m7usf5vmULAhkVF4v55DAsb0HjB2JpDqTiQ + # OKyNZ7qFzAXb2aZTecZv4tScZsS3OngsqZ3FI0T1JPmaSWBxNJY5wkf3XV7btd5L + # H9X5ShtTA7Np33XuXneu01mGhEq3boLro+vfXMHV5QHyle1F4LUFWEqtP0UmZ5wA + # rro0Y7pA8R88tu5X4iWEjQPnAsbRixwFQ9LNMD8+40e1UIguobRySnP5umErHaIh + # Kui7ZijLjbZh/dPS0IfpgahL1K6s9XhT3mD9WMvAvMkNtLewHIZZukG45mOQBrjF + # vvyYxoECgYEA+EY6YimGw0IKnUuf+5uZRXST7kDMENz1Flkcj8oZvo47hdX8/lDN + # i0y7gm3VNfHAK2R2KZPmSbtXA0DvS7kmx1/CFcmwkaakhuU5dyCHldWwSaTME3IE + # xjSZfTvlAiq9i6nUflgfkKo3Bdsiq8TYOUAv25S2SwYDH9Tx0fQwwGECgYEA3Ynt + # CHc8e4YRlGT65UQmEZ8cptmqVRyY4ClMU1xht7Pn0G1JwKRraiEL5/LndwscWf3h + # DygQuArJ28pp4d22FEW1LeXozXYUjJoz3anIA45IZ1OihS7Cx7tJB51/QNJeFdF4 + # EX/XHaVukHyYSsAxkwCUYOw3cSgZOSEddL5Wf00CgYEA7JlIlDmMwtFR+jqSmJ3c + # //Kr8zZvAnb/Xa/IZ0MrK4yyLsYR1m48o06Ztx9iO4lKIFAZx1+563QL5P7hzOEC + # kqev90GA8hzD2AXksKEgdOrymAvjq3hSEm0YBN+qS1ldzxYmec0TL7L2wq7lqJnr + # kQuZUAG1g2OUYKZ3WSUDvKECgYEAv24NSkFuG/avfiD7w9xtYNCye2KekskROLG2 + # 6FltfsWQTEQDdNkekChaF2WHqRAKwaBlNymRuNZpsuhnMerZCQ9rDWwbDF86RnyA + # 0MuCr7/kxJQ6XQcY/GnTIydu7F5bOlM0gzqKcW2f6m4fUohczf+0N0QmbDsQAJOi + # 1lwadgkCgYEA3tkCBJIPTQecfjWiLqSocS6SrwXU+r3Jw6kI3/IB6ban/nsFdHSb + # nADST7f2zZatN6XALwsLU7f2R09R39ub0AJPyfToxo7MngR1rvaUYooF3rLlaU32 + # 8DqGvGpLkZkwbtcDmcX1zQoHjUo7RvoShZoapr59ihfrkiiEsXOkuGw= + # -----END RSA PRIVATE KEY----- # Host or URL of the instance of Hyperion # This url will be especially used for OIDC/OAuth2 discovery endpoint and links send by email @@ -122,24 +122,16 @@ USE_FACTORIES: True # if True and the database is empty, it will be seeded with # ``` # Group UUIDs should be values of the GroupType enum from `app.core.groups.groupe_type.GroupType` FACTORIES_DEMO_USERS: - - firstname: Your Firstname - name: Your Name - nickname: Your Nickname - email: your-firstname.your-name@etu.ec-lyon.fr - password: Your_P@$$w0rd + - firstname: #Foucauld + name: #Bellanger + nickname: #Ñool + email: #foucauld.bellanger@etu.ec-lyon.fr + password: #azerty groups: - 0a25cb76-4b63-4fd3-b939-da6d9feabf28 # admin - 45649735-866a-49df-b04b-a13c74fd5886 # AE - 1f841bd9-00be-41a7-96e1-860a18a46105 # eclair - - firstname: Foucauld - name: Bellanger - nickname: Ñool - email: foucauld.bellanger@etu.ec-lyon.fr - password: azerty - groups: - - 1f841bd9-00be-41a7-96e1-860a18a46105 - - 45649735-866a-49df-b04b-a13c74fd5886 - - 4ec5ae77-f955-4309-96a5-19cc3c8be71c + # - firstname: ... ##################################### # SMTP configuration using starttls # From 894b65b9154e59e9a2cfbbae420ef20cb78092cc Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Sun, 19 Oct 2025 11:10:27 +0200 Subject: [PATCH 41/42] Rename to requirements.txt --- .github/workflows/lintandformat.yml | 2 +- .github/workflows/test.yml | 2 +- README.md | 2 +- requirements-dev.txt | 2 +- requirements-common.txt => requirements.txt | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename requirements-common.txt => requirements.txt (100%) diff --git a/.github/workflows/lintandformat.yml b/.github/workflows/lintandformat.yml index c2e0323c01..6838aec746 100644 --- a/.github/workflows/lintandformat.yml +++ b/.github/workflows/lintandformat.yml @@ -26,7 +26,7 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/uv - key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-uv-${{ hashFiles('requirements-common.txt', 'requirements-dev.txt') }} + key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-uv-${{ hashFiles('requirements.txt', 'requirements-dev.txt') }} - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0fce09ddc3..5e1eadf77c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,7 +64,7 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/uv - key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-uv-${{ hashFiles('requirements-common.txt', 'requirements-dev.txt') }} + key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-uv-${{ hashFiles('requirements.txt', 'requirements-dev.txt') }} - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh diff --git a/README.md b/README.md index 3519ca3b7a..3343cf5ff3 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ pyenv activate hyperion ### About Jellyfish and Rust -If you don't have Rust installed or don't want to install it, decrease the version of `jellyfish` to `0.10.0` in the `requirements-common.txt` file: +If you don't have Rust installed or don't want to install it, decrease the version of `jellyfish` to `0.10.0` in the `requirements.txt` file: ``` jellyfish==0.10.0 # String Matching diff --git a/requirements-dev.txt b/requirements-dev.txt index c949a25188..c45420ac10 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,4 @@ --r requirements-common.txt +-r requirements.txt aiosqlite==0.20.0 boto3-stubs[essential]==1.38.23 google-auth-stubs==0.3.0 diff --git a/requirements-common.txt b/requirements.txt similarity index 100% rename from requirements-common.txt rename to requirements.txt From 39a31d39c2943e086caa4ffe3c1b3647d7dd2c2c Mon Sep 17 00:00:00 2001 From: Marc-Andrieu <146140470+Marc-Andrieu@users.noreply.github.com> Date: Sun, 19 Oct 2025 00:33:12 +0200 Subject: [PATCH 42/42] Fix: make profile pictures imported in Synapse again (#881) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description ### Summary Bug: his unexpected comment explains why new users don't have their avatar imported through our SSO to the Matrix server. Feature: it seems the MAS (Matrix Authentication Service) now supports the `picture` claim of the OIDC scope, so we add it [back]. Source: https://github.com/element-hq/matrix-authentication-service/blob/1bd1b00524a62e365cf06b3745d298a53df69c90/crates/jose/src/claims.rs#L525 ## Type of Change We present it as a feature but it's actually a bug fix... - [x] 🐛 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (non-breaking change which adds functionality) - [ ] 🔨 Refactor (non-breaking change that neither fixes a bug nor adds a feature) - [ ] 🔧 Infra CI/CD (changes to configs of workflows) - [ ] 💥 BREAKING CHANGE (fix or feature that require a new minimal version of the front-end) ## Impact & Scope - [ ] Core functionality changes - [ ] Single module changes - [ ] Multiple modules changes - [ ] Database migrations required - [x] Other: 3rd party service integration ## Testing - [ ] Added/modified tests that pass the CI - [ ] Tested in a pre-prod - [ ] Tested this locally - [x] Will be tested in prod directly... ## Documentation - [ ] Updated docs accordingly (docs.myecl.fr) : - [ ] Code includes docstrings - [x] No documentation needed --- app/utils/auth/providers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/utils/auth/providers.py b/app/utils/auth/providers.py index 2780ac572c..0fbf5d8246 100644 --- a/app/utils/auth/providers.py +++ b/app/utils/auth/providers.py @@ -240,7 +240,7 @@ def get_userinfo(cls, user: models_users.CoreUser): return { "sub": user.id, - # "picture": f"https://hyperion.myecl.fr/users/{user.id}/profile-picture", + "picture": f"https://hyperion.myecl.fr/users/{user.id}/profile-picture", # Matrix does not support special characters in username "username": username, "displayname": user.full_name,