diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e188a5b..aac817f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,3 +9,13 @@ repos: rev: v0.8.1 hooks: - id: ruff-format + + - repo: local + hooks: + - id: pydantic-settings-export + name: Generate config documentation + entry: bash -c 'PYTHONPATH=$PWD pydantic-settings-export && python -c "import re; content = open(\"CONFIGURATION.md\").read(); content = re.sub(r\"/home/[^/]+/[^|]+/app\", \"./app\", content); open(\"CONFIGURATION.md\", \"w\").write(content)"' + language: system + # only run this hook if settings have changed + files: ^app/core/config\.py$ + pass_filenames: false diff --git a/CONFIGURATION.md b/CONFIGURATION.md new file mode 100644 index 0000000..6274107 --- /dev/null +++ b/CONFIGURATION.md @@ -0,0 +1,27 @@ +# Configuration + +Here you can find all available configuration options using ENV variables. + +## Settings + +| Name | Type | Default | Description | Example | +|------------------------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `PROJECT_ROOT` | `string` | `"./app"` | The project directory. Used to find project files (e.g., assets). Auto-generated by default, but can be overridden if needed. | `"./app"` | +| `REPORTING_GATEKEEPER_USERNAME` | `string` | *required* | | | +| `REPORTING_GATEKEEPER_PASSWORD` | `string` | *required* | | | +| `REPORTING_BACKEND_CORS_ORIGINS` | `Any` | *required* | | | +| `REPORTING_POSTGRES_USER` | `string` | *required* | | | +| `REPORTING_POSTGRES_PASSWORD` | `string` | *required* | | | +| `REPORTING_POSTGRES_DB` | `string` | *required* | | | +| `REPORTING_POSTGRES_HOST` | `string` | *required* | | | +| `REPORTING_POSTGRES_PORT` | `integer` | *required* | | | +| `REPORTING_SERVICE_NAME` | `string` | *required* | | | +| `REPORTING_SERVICE_PORT` | `integer` | *required* | | | +| `REPORTING_USING_GATEKEEPER` | `boolean` | `true` | | `true` | +| `REPORTING_GATEKEEPER_BASE_URL` | `string` | *required* | | | +| `REPORTING_FARMCALENDAR_BASE_URL` | `string` | `"api/proxy/farmcalendar/api/v1"` | | `"api/proxy/farmcalendar/api/v1"` | +| `REPORTING_FARMCALENDAR_URLS` | `object` | `{"irrigations":"/IrrigationOperations/","fertilization":"/FertilizationOperations/","pesticides":"/CropProtectionOperations/","pest":"/Pesticides/","activity_types":"/FarmCalendarActivityTypes/","observations":"/Observations/","operations":"/CompostOperations/","turning_operations":"/CompostTurningOperations/","activities":"/FarmCalendarActivities/","parcel":"/FarmParcels/","animals":"/FarmAnimals/","materials":"/AddRawMaterialOperations/","machines":"/AgriculturalMachines/","farm":"/Farm/"}` | | `{"irrigations":"/IrrigationOperations/","fertilization":"/FertilizationOperations/","pesticides":"/CropProtectionOperations/","pest":"/Pesticides/","activity_types":"/FarmCalendarActivityTypes/","observations":"/Observations/","operations":"/CompostOperations/","turning_operations":"/CompostTurningOperations/","activities":"/FarmCalendarActivities/","parcel":"/FarmParcels/","animals":"/FarmAnimals/","materials":"/AddRawMaterialOperations/","machines":"/AgriculturalMachines/","farm":"/Farm/"}` | +| `PDF_DIRECTORY` | `string` | `"user_reports/"` | | `"user_reports/"` | +| `SQLALCHEMY_DATABASE_URI` | `string` \| `NoneType` | `null` | | `null` | +| `JWT_ACCESS_TOKEN_EXPIRATION_TIME` | `integer` | *required* | | | +| `JWT_SIGNING_KEY` | `string` | *required* | | | diff --git a/README.md b/README.md index 998d86a..98ab938 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ docker compose build docker compose up ``` +See [CONFIGURATION.md](./CONFIGURATION.md) for available environment settings. + The application will be served on http://127.0.0.1:8009 (I.E. typing localhost/docs in your browser will load the swagger documentation) Full list of APIs available you can check [here](https://editor.swagger.io/?url=https://gist.githubusercontent.com/JoleVLF/7f5771b23a44e508b82e47d5fafd9f9c/raw/) diff --git a/app/core/config.py b/app/core/config.py index d5504fe..e67e908 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1,4 +1,4 @@ -from pydantic import AnyHttpUrl, field_validator +from pydantic import field_validator, ConfigDict, Field from pydantic_settings import BaseSettings from password_validator import PasswordValidator from typing import Optional, Any @@ -7,7 +7,10 @@ class Settings(BaseSettings): - PROJECT_ROOT: str = path.dirname(path.dirname(path.realpath(__file__))) + PROJECT_ROOT: str = Field( + default=path.dirname(path.dirname(path.realpath(__file__))), + description="The project directory. Used to find project files (e.g., assets). Auto-generated by default, but can be overridden if needed.", + ) REPORTING_GATEKEEPER_USERNAME: str REPORTING_GATEKEEPER_PASSWORD: str @@ -37,7 +40,7 @@ class Settings(BaseSettings): "animals": "/FarmAnimals/", "materials": "/AddRawMaterialOperations/", "machines": "/AgriculturalMachines/", - "farm": "/Farm/" + "farm": "/Farm/", } PDF_DIRECTORY: str = "user_reports/" @@ -59,11 +62,30 @@ def assemble_db_connection(cls, v: Optional[str], values) -> Any: return url PASSWORD_SCHEMA_OBJ: PasswordValidator = PasswordValidator() - PASSWORD_SCHEMA_OBJ.min(8).max( - 100 - ).has().uppercase().has().lowercase().has().digits().has().no().spaces() + PASSWORD_SCHEMA_OBJ: PasswordValidator = Field( + default_factory=lambda: PasswordValidator() + .min(8) + .max(100) + .has() + .uppercase() + .has() + .lowercase() + .has() + .digits() + .has() + .no() + .spaces(), + exclude=True, + ) JWT_ACCESS_TOKEN_EXPIRATION_TIME: int JWT_SIGNING_KEY: str + # https://docs.pydantic.dev/latest/concepts/config/ + model_config = ConfigDict( + # allows PasswordValidator to be used as a field in the Settings class + arbitrary_types_allowed=True, + env_file=".env", + ) + settings = Settings() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9c789e9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[tool.pydantic_settings_export] +project_dir = "." +default_settings = ["app.core.config:Settings"] + +[[tool.pydantic_settings_export.generators.markdown]] +paths = ["CONFIGURATION.md"] diff --git a/requirements.txt b/requirements.txt index be02e6d..ed51463 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ alembic==1.13.1 # DB migrations requests==2.32.3 psycopg2==2.9.9 # PSQL driver password-validator==1.0 # Enforceable rules for passwords -pydantic-settings==2.2.1 # Pydantic settings options [donated to the python-org, not part of the main package anymore] +pydantic-settings==2.8.1 # Pydantic settings options [donated to the python-org, not part of the main package anymore] passlib==1.7.4 # For password managment PyJWT==2.8.0 # Instead of jose (has a CVE) argon2_cffi==23.1.0 # Backend for Argon encryption @@ -25,4 +25,4 @@ httpx==0.27.2 black==24.10.0 # Python formatter ruff==0.8.1 pre-commit==4.0.1 - +pydantic-settings-export==1.0.3