diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95d8b21e..a2619a78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,76 +15,74 @@ env: IMAGE_NAME: maykinmedia/opendms DJANGO_SETTINGS_MODULE: opendms.conf.ci DOCKER_BUILDKIT: '1' + DB_PASSWORD: '' + DB_USER: postgres jobs: - setup: - name: Set up the build variables - runs-on: ubuntu-latest - outputs: - tag: ${{ steps.vars.outputs.tag }} - git_hash: ${{ steps.vars.outputs.git_hash }} - + # determine changed files to decide if certain jobs can be skipped or not + changed-files: + runs-on: ubuntu-latest # windows-latest | macos-latest + name: Determine changed files steps: - - name: Extract version information - id: vars - run: | - # Strip git ref prefix from version - VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') - # Strip "v" prefix from tag name (if present at all) - [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + - uses: actions/checkout@v4 + with: + fetch-depth: 0 - # Use Docker `latest` tag convention - [ "$VERSION" == "main" ] && VERSION=latest + - name: Get changed PY files + id: changed-py-files + run: bin/check_changed_files.sh ^src/.*\.py$ - # PRs result in version 'merge' -> transform that into 'latest' - [ "$VERSION" == "merge" ] && VERSION=latest + - name: Get changed requirements files + id: changed-requirements + run: bin/check_changed_files.sh ^requirements/.*\.txt$ - echo "tag=${VERSION}" >> $GITHUB_OUTPUT - echo "git_hash=${GITHUB_SHA}" >> $GITHUB_OUTPUT + outputs: + changed-py-files: ${{ steps.changed-py-files.outputs.any_changed }} + changed-requirements: ${{ steps.changed-requirements.outputs.any_changed }} tests: - name: Run the Django test suite + name: Tests (PG ${{ matrix.postgres }}) runs-on: ubuntu-latest + needs: + - changed-files + + # only run tests if source files have changed (e.g. skip for PRs that only update docs) + if: ${{ needs.changed-files.outputs.changed-py-files == 'true'|| needs.changed-files.outputs.changed-requirements == 'true'|| github.event_name == 'push' }} + + strategy: + matrix: + postgres: ["14", "15", "16", "17"] services: postgres: - image: postgres:17 + image: postgres:${{ matrix.postgres }} env: POSTGRES_HOST_AUTH_METHOD: trust ports: - 5432:5432 - # Needed because the postgres container does not provide a healthcheck - options: >- - --name postgres - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 redis: - image: redis:6 + image: redis:8 ports: - 6379:6379 + steps: - uses: actions/checkout@v4 - name: Set up backend environment uses: maykinmedia/setup-django-backend@v1.3 with: python-version: '3.14' - optimize-postgres: 'yes' - pg-service: 'postgres' - setup-node: 'no' + setup-node: true - name: Run tests run: | - python src/manage.py compilemessages python src/manage.py collectstatic --noinput --link coverage run src/manage.py test src env: SECRET_KEY: dummy - DB_USER: postgres - DB_PASSWORD: '' - name: Publish coverage report uses: codecov/codecov-action@v4 @@ -115,79 +113,61 @@ jobs: npx playwright install npm run test - # docs: - # name: Build and check documentation - # runs-on: ubuntu-latest - - # steps: - # - uses: actions/checkout@v4 - # - uses: maykinmedia/setup-django-backend@v1.3 - # with: - # python-version: '3.14' - # setup-node: 'no' - # # apt-packages: 'gettext postgresql-client' # the default - - # - name: Build and test docs - # run: | - # export OPENSSL_CONF=$(pwd)/openssl.conf - # pytest check_sphinx.py -v --tb=auto - # working-directory: docs - - docker_build: - name: Build Docker image + check-envvar-docs: runs-on: ubuntu-latest - outputs: - image_tag: ${{ steps.image_build.outputs.image_tag }} - - needs: - - setup + name: Documentation build steps: - uses: actions/checkout@v4 + - name: Set up backend environment + uses: maykinmedia/setup-django-backend@v1.3 + with: + python-version: '3.14' + apt-packages: "libgdal-dev gdal-bin" + setup-node: false - - name: Build the production Docker image - id: image_build + - name: Generate environment variable documentation using OAf and check if it was updated run: | - image_tag="$IMAGE_NAME:$RELEASE_VERSION" - echo "image_tag=${image_tag}" >> $GITHUB_OUTPUT - docker build . \ - --tag $image_tag \ - --build-arg COMMIT_HASH=${{ needs.setup.outputs.git_hash }} \ - --build-arg RELEASE=${{ needs.setup.outputs.tag }} \ - env: - RELEASE_VERSION: ${{ needs.setup.outputs.tag }} + bin/generate_envvar_docs.sh + changes=$(git diff docs/installation/config/env_configuration.rst) + if [ ! -z "$changes" ]; then + echo $changes + echo "Please update the environment documentation by running \`bin/generate_envvar_docs.sh\`" + exit 1 + fi + + store-reusable-workflow-vars: + name: create values which can be passed through a reusable workflow + runs-on: ubuntu-latest + outputs: + image-name: ${{ steps.image-name.outputs.image-name }} - - run: docker image save -o image.tar $IMAGE_NAME:${{ needs.setup.outputs.tag }} - - name: Store image artifact - uses: actions/upload-artifact@v4 - with: - name: docker-image - path: image.tar - retention-days: 1 + steps: + - run: echo "image-name=$IMAGE_NAME" >> $GITHUB_OUTPUT + name: 'Store the docker image name' + id: image-name -# docker_push: + open-api-ci: + uses: maykinmedia/open-api-workflows/.github/workflows/ci.yml@v6 + needs: + - store-reusable-workflow-vars + with: + apt-packages: 'graphviz graphviz-dev' + main-branch: 'main' + run-docs: true + python-version: '3.14' + docker-image-name: ${{ needs.store-reusable-workflow-vars.outputs.image-name }} + django-settings-module: opendms.conf.ci + +# open-api-publish: +# uses: maykinmedia/open-api-workflows/.github/workflows/publish.yml@v6 # needs: +# - store-reusable-workflow-vars +# - open-api-ci # - tests -# - docker_build -# -# name: Push Docker image -# runs-on: ubuntu-latest -# if: github.event_name == 'push' # Exclude PRs -# -# steps: -# - name: Download built image -# uses: actions/download-artifact@v4 -# with: -# name: docker-image -# -# - name: Load image -# run: | -# docker image load -i image.tar -# -# - name: Log into registry -# run: -# echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} -# --password-stdin -# -# - name: Push the Docker image (production) -# run: docker push ${{ needs.docker_build.outputs.image_tag }} +# with: +# docker-image-name: ${{ needs.store-reusable-workflow-vars.outputs.image-name }} +# repository-owner: 'maykinmedia' +# secrets: +# docker-username: ${{ secrets.DOCKER_USERNAME }} +# docker-token: ${{ secrets.DOCKER_TOKEN }} diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index ec020cfd..0e8cbf57 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -1,89 +1,23 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. name: Code quality checks -# Run this workflow every time a new commit pushed to your repository on: push: branches: - main - - stable/* - tags: - - '*' pull_request: workflow_dispatch: jobs: - ruff: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/ruff-action@v3 - - name: Linting - run: ruff check - - name: Check formatting - run: ruff format --check - - migrations: - name: Check for model changes not present in migrations - runs-on: ubuntu-latest - - services: - postgres: - image: postgres:17 - env: - POSTGRES_HOST_AUTH_METHOD: trust - ports: - - 5432:5432 - # Needed because the postgres container does not provide a healthcheck - options: - --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - - steps: - - uses: actions/checkout@v4 - - name: Set up backend environment - uses: maykinmedia/setup-django-backend@v1.3 - with: - python-version: '3.14' - setup-node: 'no' - - - name: Run makemigrations to check for missing migrations - run: | - src/manage.py makemigrations \ - --check \ - --dry-run - env: - DJANGO_SETTINGS_MODULE: "opendms.conf.ci" - DEBUG: 'true' - SECRET_KEY: dummy - DB_USER: postgres - DB_NAME: postgres - DB_PASSWORD: '' - - translations: - name: Check for missing translations - runs-on: ubuntu-latest - - services: - postgres: - image: postgres:17 - env: - POSTGRES_HOST_AUTH_METHOD: trust - ports: - - 5432:5432 - # Needed because the postgres container does not provide a healthcheck - options: - --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - - steps: - - uses: actions/checkout@v4 - - name: Set up backend environment - uses: maykinmedia/setup-django-backend@v1.3 - with: - python-version: '3.14' - setup-node: 'no' - - - name: Run makemessages to check for missing translations - run: | - python src/manage.py makemessages --all - git diff --exit-code - env: - DJANGO_SETTINGS_MODULE: "opendms.conf.ci" + open-api-workflow-code-quality: + uses: maykinmedia/open-api-workflows/.github/workflows/code-quality.yml@v6 + with: + python-version: "3.14" + node-version: "24" + + django-settings-module: "opendms.conf.ci" + django-secret-key: dummy diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e8bc55eb..a5be6095 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,39 +1,14 @@ -name: 'CodeQL' +name: "CodeQL" on: push: branches: - main - stable/* + pull_request: schedule: - cron: '32 20 * * 3' jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ['javascript', 'python'] - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - - - name: Perform CodeQL Analysis - if: ${{ github.event.repository.visibility == 'public' }} # Seems to fail on private repo's - uses: github/codeql-action/analyze@v3 + open-api-workflow-code-analysis: + uses: maykinmedia/open-api-workflows/.github/workflows/code-analysis.yml@v6 diff --git a/.github/workflows/oaf-check.yml b/.github/workflows/oaf-check.yml new file mode 100644 index 00000000..1ce0e1a4 --- /dev/null +++ b/.github/workflows/oaf-check.yml @@ -0,0 +1,19 @@ +name: Check Open API Framework Version + +on: + push: + branches: + - main + tags: + - '*' + workflow_dispatch: + schedule: + - cron: '0 7 * * 1' + + +jobs: + open-api-workflow-check-oas: + uses: maykinmedia/open-api-workflows/.github/workflows/oaf-check.yml@v6 + + with: + python-version: '3.14' diff --git a/.gitignore b/.gitignore index 8f04c3c0..8b85cccb 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ local.py /static/ /mail/ /log/*.log* +/log/*.jsonl* /log/nginx/*.log* /.env diff --git a/Dockerfile b/Dockerfile index 1dcd4cba..7c9836bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -88,7 +88,8 @@ COPY --from=frontend-build /app/dist /app/src/opendms/frontend # copy source code COPY ./src /app/src -RUN useradd -M -u 1000 maykin \ +RUN groupadd -g 1000 maykin \ + && useradd -M -u 1000 -g 1000 maykin \ && chown -R maykin:maykin /app # drop privileges diff --git a/bin/check_changed_files.sh b/bin/check_changed_files.sh new file mode 100755 index 00000000..c7eb5213 --- /dev/null +++ b/bin/check_changed_files.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# Determine the base ref or fallback to the last commit +if [ -n "$GITHUB_BASE_REF" ]; then + BASE_REF="origin/$GITHUB_BASE_REF" +else + BASE_REF="HEAD^" # Compare with the previous commit on main branch +fi + +git fetch --all + +# Get the list of files that were changed between the base branch and the current commit +CHANGED_FILES=$(git diff --name-only $BASE_REF...HEAD) +if echo "$CHANGED_FILES" | grep -q "$1"; then + echo "Files were changed!" + echo "any_changed=true" >> $GITHUB_OUTPUT +else + echo "No changes detected" + echo "any_changed=false" >> $GITHUB_OUTPUT +fi diff --git a/bin/compile_dependencies.sh b/bin/compile_dependencies.sh index a26834c9..6e3dda11 100755 --- a/bin/compile_dependencies.sh +++ b/bin/compile_dependencies.sh @@ -14,29 +14,25 @@ set -ex command -v uv || (echo "uv not found on PATH. Install it https://astral.sh/uv" >&2 && exit 1) -cwd="${PWD}" -toplevel=$(git rev-parse --show-toplevel) - -cd "${toplevel}" +root_dir=$(git rev-parse --show-toplevel) export UV_CUSTOM_COMPILE_COMMAND="./bin/compile_dependencies.sh" # Base (& prod) deps uv pip compile \ - --output-file requirements/base.txt \ + --output-file "$root_dir/requirements/base.txt" \ "$@" \ - requirements/base.in + "$root_dir/requirements/base.in" # Dependencies for testing uv pip compile \ - --output-file requirements/ci.txt \ + --output-file "$root_dir/requirements/ci.txt" \ "$@" \ - requirements/test-tools.in + "$root_dir/requirements/test-tools.in" \ + "$root_dir/requirements/docs.in" # Dev depedencies - exact same set as CI + some extra tooling uv pip compile \ - --output-file requirements/dev.txt \ + --output-file "$root_dir/requirements/dev.txt" \ "$@" \ - requirements/dev.in - -cd "${cwd}" + "$root_dir/requirements/dev.in" diff --git a/bin/generate_envvar_docs.sh b/bin/generate_envvar_docs.sh new file mode 100755 index 00000000..bada72e7 --- /dev/null +++ b/bin/generate_envvar_docs.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Generates the documentation for environment variables +src/manage.py generate_envvar_docs --file docs/installation/config/env_configuration.rst --exclude-group Celery diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css new file mode 100644 index 00000000..60b010a0 --- /dev/null +++ b/docs/_static/theme_overrides.css @@ -0,0 +1,35 @@ +/* override table width restrictions */ +@media screen and (min-width: 767px) { + + .wy-table-responsive table td { + /* !important prevents the common CSS stylesheets from overriding + this as on RTD they are loaded after this stylesheet */ + white-space: normal !important; + } + + .wy-table-responsive table td:first-child { + white-space: nowrap !important; + } + + .wy-table-responsive table { + background-color: white; + } + + .wy-table-responsive { + overflow: visible !important; + } +} + +.wy-side-nav-search { + background-color: #04A5BB; +} + +.rst-content a:link, +.rst-content a:visited { + color: #017092; +} + +.rst-content a:focus, +.rst-content a:hover { + color: #051F31; +} diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 00000000..76888fe1 --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1,3 @@ +.. _changelog: + +.. include:: ../CHANGELOG.rst diff --git a/docs/check_sphinx.py b/docs/check_sphinx.py new file mode 100644 index 00000000..cc1003a1 --- /dev/null +++ b/docs/check_sphinx.py @@ -0,0 +1,17 @@ +import subprocess + + +def test_linkcheck(tmpdir): + doctrees = tmpdir.join("doctrees") + htmldir = tmpdir.join("html") + subprocess.check_call( + ["sphinx-build", "-W", "-blinkcheck", "-d", str(doctrees), ".", str(htmldir)], + ) + + +def test_build_docs(tmpdir): + doctrees = tmpdir.join("doctrees") + htmldir = tmpdir.join("html") + subprocess.check_call( + ["sphinx-build", "-W", "-bhtml", "-d", str(doctrees), ".", str(htmldir)], + ) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..294cdf87 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,125 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- +import os +import sys + +import django +from django.utils.translation import activate + +sys.path.insert(0, os.path.abspath("../src")) +os.environ["LOG_REQUESTS"] = "false" + +import opendms # noqa isort:skip + +# Import as private variable to avoid errors on build +from importlib.metadata import version as _version + +from opendms.setup import setup_env # noqa isort:skip + +setup_env() +django.setup() + +# -- Project information ----------------------------------------------------- + +project = "opendms" +copyright = "Maykin B.V. 2025" # noqa +author = opendms.__author__ + +# The full version, including alpha/beta/rc tags +release = opendms.__version__ + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.todo", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", + "sphinx.ext.autodoc", + "sphinx.ext.graphviz", + "django_setup_configuration.documentation.setup_config_example", + "django_setup_configuration.documentation.setup_config_usage", + "vng_api_common.diagrams.uml_images", + "sphinx_tabs.tabs", + "recommonmark", + # "sphinx_markdown_tables", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# Also set the language to English for Django, to make sure that any translatable text +# is also shown in English (for instance the help texts for setup configuration examples) +activate("en") + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".pytest_cache", "_archive"] + +source_suffix = [".rst", ".md"] + +# Datamodel image settings +graphviz_output_format = "png" + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +# html_logo = "logo.svg" +html_theme = "sphinx_rtd_theme" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] +html_css_files = [ + "theme_overrides.css", # override wide tables with word wrap +] + +todo_include_todos = True + +linkcheck_retries = 3 + +linkcheck_ignore = [ + r"urn:*", + r"https?://.*\.gemeente.nl", + r"http://localhost:\d+/", + r"https://.*sentry.*", + r"https://example.com*", + r"https://portal.azure.com*", + r"https://.*kvk\.nl*", + r"https://gdpr.eu*", +] + +extlinks = {} + +django_structlog_version = _version("django-structlog") +oaf_version = _version("open-api-framework") +intersphinx_mapping = { + "django-structlog": ( + f"https://django-structlog.readthedocs.io/en/{django_structlog_version}", + None, + ), + "oaf": ( + f"https://open-api-framework.readthedocs.io/en/{oaf_version}/", + None, + ), +} diff --git a/docs/index.rst b/docs/index.rst index 5091aa33..85fde18c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,15 +1,16 @@ .. _index: -=================== +====================== +Open DMS Documentation +====================== -=================== - -Welcome to the documentation for the project. - - -Documentation -============= +Getting Started +--------------- .. toctree:: - :maxdepth: 3 + :maxdepth: 3 + :hidden: + installation/index + testing + changelog diff --git a/docs/install/dev.rst b/docs/install/dev.rst deleted file mode 100644 index 8a84ecc3..00000000 --- a/docs/install/dev.rst +++ /dev/null @@ -1,38 +0,0 @@ -.. _install_development: - -======================= -Development environment -======================= - -Quick start -=========== - -#. Navigate to the location where you want to place your project. - -#. Get the code:: - - git clone git@bitbucket.org:maykinmedia/opendms.git - cd opendms - -#. Bootstrap the virtual environment and install all required libraries. The - ``bootstrap.py`` script basically sets the proper Django settings file to be - used:: - - python bootstrap.py - -#. Activate your virtual environment and create the statics and database:: - - source env/bin/activate # or, workon if you use virtualenvwrapper - npm install - npm run build - python src/manage.py collectstatic --link - python src/manage.py migrate - - -Next steps ----------- - -You can now run your installation and point your browser to the address given -by this command:: - - python src/manage.py runserver diff --git a/docs/install/index.rst b/docs/install/index.rst deleted file mode 100644 index 1709cb6d..00000000 --- a/docs/install/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _install_index: - -============ -Installation -============ - -This section briefly describes how the project is intended to be installed in -development, staging and production environments. - -.. toctree:: - :maxdepth: 2 - - development - staging - production diff --git a/docs/install/production.rst b/docs/install/production.rst deleted file mode 100644 index 4bb2e350..00000000 --- a/docs/install/production.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. _install_production: - -====================== -Production environment -====================== diff --git a/docs/install/staging.rst b/docs/install/staging.rst deleted file mode 100644 index 4e31e736..00000000 --- a/docs/install/staging.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. _install_staging: - -=================== -Staging environment -=================== diff --git a/docs/installation/config/env_configuration.rst b/docs/installation/config/env_configuration.rst new file mode 100644 index 00000000..c0159a6b --- /dev/null +++ b/docs/installation/config/env_configuration.rst @@ -0,0 +1,145 @@ +.. _installation_env_config: + +=================================== +Environment configuration reference +=================================== + + + +Available environment variables +=============================== + + +Required +-------- + +* ``SECRET_KEY``: Secret key that's used for certain cryptographic utilities. . +* ``ALLOWED_HOSTS``: a comma separated (without spaces!) list of domains that serve the installation. Used to protect against Host header attacks. Defaults to: ``(empty string)``. +* ``CACHE_DEFAULT``: redis cache address for the default cache (this **MUST** be set when using Docker). Defaults to: ``localhost:6379/0``. +* ``CACHE_AXES``: redis cache address for the brute force login protection cache (this **MUST** be set when using Docker). Defaults to: ``localhost:6379/0``. +* ``EMAIL_HOST``: hostname for the outgoing e-mail server (this **MUST** be set when using Docker). Defaults to: ``localhost``. + + +Database +-------- + +* ``DB_NAME``: name of the PostgreSQL database. Defaults to: ``opendms``. +* ``DB_USER``: username of the database user. Defaults to: ``opendms``. +* ``DB_PASSWORD``: password of the database user. Defaults to: ``opendms``. +* ``DB_HOST``: hostname of the PostgreSQL database. Defaults to ``db`` for the docker environment, otherwise defaults to ``localhost``. +* ``DB_PORT``: port number of the database. Defaults to: ``5432``. +* ``DB_CONN_MAX_AGE``: The lifetime of a database connection, as an integer of seconds. Use 0 to close database connections at the end of each request — Django’s historical behavior. This setting is ignored if connection pooling is used. Defaults to: ``60``. +* ``DB_POOL_ENABLED``: **Experimental:** Whether to use connection pooling. This feature is not yet recommended for production use. See the documentation for details: https://open-api-framework.readthedocs.io/en/latest/connection_pooling.html. Defaults to: ``False``. +* ``DB_POOL_MIN_SIZE``: The minimum number of connection the pool will hold. The pool will actively try to create new connections if some are lost (closed, broken) and will try to never go below min_size. Defaults to: ``4``. +* ``DB_POOL_MAX_SIZE``: The maximum number of connections the pool will hold. If None, or equal to min_size, the pool will not grow or shrink. If larger than min_size, the pool can grow if more than min_size connections are requested at the same time and will shrink back after the extra connections have been unused for more than max_idle seconds. Defaults to: ``None``. +* ``DB_POOL_TIMEOUT``: The default maximum time in seconds that a client can wait to receive a connection from the pool (using connection() or getconn()). Note that these methods allow to override the timeout default. Defaults to: ``30``. +* ``DB_POOL_MAX_WAITING``: Maximum number of requests that can be queued to the pool, after which new requests will fail, raising TooManyRequests. 0 means no queue limit. Defaults to: ``0``. +* ``DB_POOL_MAX_LIFETIME``: The maximum lifetime of a connection in the pool, in seconds. Connections used for longer get closed and replaced by a new one. The amount is reduced by a random 10% to avoid mass eviction. Defaults to: ``3600``. +* ``DB_POOL_MAX_IDLE``: Maximum time, in seconds, that a connection can stay unused in the pool before being closed, and the pool shrunk. This only happens to connections more than min_size, if max_size allowed the pool to grow. Defaults to: ``600``. +* ``DB_POOL_RECONNECT_TIMEOUT``: Maximum time, in seconds, the pool will try to create a connection. If a connection attempt fails, the pool will try to reconnect a few times, using an exponential backoff and some random factor to avoid mass attempts. If repeated attempts fail, after reconnect_timeout second the connection attempt is aborted and the reconnect_failed() callback invoked. Defaults to: ``300``. +* ``DB_POOL_NUM_WORKERS``: Number of background worker threads used to maintain the pool state. Background workers are used for example to create new connections and to clean up connections when they are returned to the pool. Defaults to: ``3``. + + +Logging +------- + +* ``LOG_STDOUT``: whether to log to stdout or not. Defaults to: ``True``. +* ``LOG_LEVEL``: control the verbosity of logging output. Available values are ``CRITICAL``, ``ERROR``, ``WARNING``, ``INFO`` and ``DEBUG``. Defaults to: ``INFO``. +* ``LOG_QUERIES``: enable (query) logging at the database backend level. Note that you must also set ``DEBUG=1``, which should be done very sparingly!. Defaults to: ``False``. +* ``LOG_REQUESTS``: enable logging of the outgoing requests. This must be enabled along with `LOG_OUTGOING_REQUESTS_DB_SAVE` to save outgoing request logs in the database. Defaults to: ``False``. +* ``LOG_FORMAT_CONSOLE``: The format for the console logging handler, possible options: ``json``, ``plain_console``. Defaults to: ``json``. +* ``ENABLE_STRUCTLOG_REQUESTS``: enable structured logging of requests. Defaults to: ``True``. +* ``LOG_OUTGOING_REQUESTS_EMIT_BODY``: Whether or not outgoing request bodies should be logged. Defaults to: ``True``. +* ``LOG_OUTGOING_REQUESTS_DB_SAVE``: Whether or not outgoing request logs should be saved to the database. Defaults to: ``False``. +* ``LOG_OUTGOING_REQUESTS_DB_SAVE_BODY``: Whether or not outgoing request bodies should be saved to the database. Defaults to: ``True``. +* ``LOG_OUTGOING_REQUESTS_MAX_AGE``: The amount of time after which request logs should be deleted from the database. Defaults to: ``7``. + + +Cross-Origin-Resource-Sharing +----------------------------- + +* ``CORS_ALLOW_ALL_ORIGINS``: allow cross-domain access from any client. Defaults to: ``False``. +* ``CORS_ALLOWED_ORIGINS``: explicitly list the allowed origins for cross-domain requests. Example: http://localhost:3000,https://some-app.gemeente.nl. Defaults to: ``[]``. +* ``CORS_ALLOWED_ORIGIN_REGEXES``: same as ``CORS_ALLOWED_ORIGINS``, but supports regular expressions. Defaults to: ``[]``. +* ``CORS_EXTRA_ALLOW_HEADERS``: headers that are allowed to be sent as part of the cross-domain request. By default, Authorization, Accept-Crs and Content-Crs are already included. The value of this variable is added to these already included headers. Defaults to: ``[]``. + + +Elastic APM +----------- + +* ``ELASTIC_APM_SERVER_URL``: URL where Elastic APM is hosted. Defaults to: ``None``. +* ``ELASTIC_APM_SERVICE_NAME``: Name of the service for this application in Elastic APM. Defaults to ``opendms - ``. +* ``ELASTIC_APM_SECRET_TOKEN``: Token used to communicate with Elastic APM. Defaults to: ``default``. +* ``ELASTIC_APM_TRANSACTION_SAMPLE_RATE``: By default, the agent will sample every transaction (e.g. request to your service). To reduce overhead and storage requirements, set the sample rate to a value between 0.0 and 1.0. Defaults to: ``0.1``. + + +Content Security Policy +----------------------- + +* ``CSP_EXTRA_DEFAULT_SRC``: Extra default source URLs for CSP other than ``self``. Used for ``img-src``, ``style-src`` and ``script-src``. Defaults to: ``[]``. +* ``CSP_EXTRA_FORM_ACTION``: Additional `form-action` sources. Defaults to: ``[]``. +* ``CSP_FORM_ACTION``: Override the default `form-action` sources. Defaults to: ``['"\'self\'"']``. +* ``CSP_EXTRA_IMG_SRC``: Extra `img-src` sources. Defaults to: ``[]``. +* ``CSP_OBJECT_SRC``: `object-src` sources. Defaults to: ``['"\'none\'"']``. +* ``CSP_REPORT_URI``: URI for CSP report-uri directive. Defaults to: ``None``. +* ``CSP_REPORT_PERCENTAGE``: Fraction (between 0 and 1) of requests to include report-uri directive. Defaults to: ``0.0``. + + +Optional +-------- + +* ``SITE_ID``: The database ID of the site object. You usually won't have to touch this. Defaults to: ``1``. +* ``DEBUG``: Only set this to ``True`` on a local development environment. Various other security settings are derived from this setting!. Defaults to: ``False``. +* ``USE_X_FORWARDED_HOST``: whether to grab the domain/host from the X-Forwarded-Host header or not. This header is typically set by reverse proxies (such as nginx, traefik, Apache...). Note: this is a header that can be spoofed and you need to ensure you control it before enabling this. Defaults to: ``False``. +* ``IS_HTTPS``: Used to construct absolute URLs and controls a variety of security settings. Defaults to the inverse of ``DEBUG``. +* ``EMAIL_PORT``: port number of the outgoing e-mail server. Note that if you're on Google Cloud, sending e-mail via port 25 is completely blocked and you should use 487 for TLS. Defaults to: ``25``. +* ``EMAIL_HOST_USER``: username to connect to the mail server. Defaults to: ``(empty string)``. +* ``EMAIL_HOST_PASSWORD``: password to connect to the mail server. Defaults to: ``(empty string)``. +* ``EMAIL_USE_TLS``: whether to use TLS or not to connect to the mail server. Should be True if you're changing the ``EMAIL_PORT`` to 487. Defaults to: ``False``. +* ``DEFAULT_FROM_EMAIL``: The default email address from which emails are sent. Defaults to: ``opendms@example.com``. +* ``SESSION_COOKIE_AGE``: For how long, in seconds, the session cookie will be valid. Defaults to: ``1209600``. +* ``SESSION_COOKIE_SAMESITE``: The value of the SameSite flag on the session cookie. This flag prevents the cookie from being sent in cross-site requests thus preventing CSRF attacks and making some methods of stealing session cookie impossible.Currently interferes with OIDC. Keep the value set at Lax if used. Defaults to: ``Lax``. +* ``CSRF_COOKIE_SAMESITE``: The value of the SameSite flag on the CSRF cookie. This flag prevents the cookie from being sent in cross-site requests. Defaults to: ``Strict``. +* ``ENVIRONMENT``: An identifier for the environment, displayed in the admin depending on the settings module used and included in the error monitoring (see ``SENTRY_DSN``). The default is set according to ``DJANGO_SETTINGS_MODULE``. +* ``SUBPATH``: If hosted on a subpath, provide the value here. If you provide ``/gateway``, the component assumes its running at the base URL: ``https://somedomain/gateway/``. Defaults to an empty string. Defaults to: ``None``. +* ``RELEASE``: The version number or commit hash of the application (this is also sent to Sentry). +* ``NUM_PROXIES``: the number of reverse proxies in front of the application, as an integer. This is used to determine the actual client IP adres. On Kubernetes with an ingress you typically want to set this to 2. Defaults to: ``1``. +* ``CSRF_TRUSTED_ORIGINS``: A list of trusted origins for unsafe requests (e.g. POST). Defaults to: ``[]``. +* ``NOTIFICATIONS_DISABLED``: indicates whether or not notifications should be sent to the Notificaties API for operations on the API endpoints. Defaults to ``True`` for the ``dev`` environment, otherwise defaults to ``False``. +* ``SITE_DOMAIN``: Defines the primary domain where the application is hosted. Defaults to: ``(empty string)``. +* ``SENTRY_DSN``: URL of the sentry project to send error reports to. Default empty, i.e. -> no monitoring set up. Highly recommended to configure this. +* ``DISABLE_2FA``: Whether or not two factor authentication should be disabled. Defaults to: ``False``. + + + + + +Specifying the environment variables +===================================== + +There are two strategies to specify the environment variables: + +* provide them in a ``.env`` file +* start the component processes (with uwsgi/gunicorn/celery) in a process + manager that defines the environment variables + +Providing a .env file +--------------------- + +This is the most simple setup and easiest to debug. The ``.env`` file must be +at the root of the project - i.e. on the same level as the ``src`` directory ( +NOT *in* the ``src`` directory). + +The syntax is key-value: + +.. code:: + + SOME_VAR=some_value + OTHER_VAR="quoted_value" + + +Provide the envvars via the process manager +------------------------------------------- + +If you use a process manager (such as supervisor/systemd), use their techniques +to define the envvars. The component will pick them up out of the box. diff --git a/docs/installation/config/index.rst b/docs/installation/config/index.rst new file mode 100644 index 00000000..1140b1b8 --- /dev/null +++ b/docs/installation/config/index.rst @@ -0,0 +1,12 @@ +.. _configuration_index: + + +============= +Configuration +============= + +.. toctree:: + :maxdepth: 1 + :caption: Further reading + + env_configuration diff --git a/docs/installation/index.rst b/docs/installation/index.rst new file mode 100644 index 00000000..7689221a --- /dev/null +++ b/docs/installation/index.rst @@ -0,0 +1,18 @@ +.. _installation_index: + +============ +Installation +============ + +In addition to making its source code available publicly, the reference +implementation for Open DMS are also maintained and work out-of-the-box for most use cases. + +For the sake of simplicity, we have chosen to use Docker and Docker Compose for this. + +.. toctree:: + :maxdepth: 1 + :caption: Further reading + + config/index + + diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 00000000..c5fcf3b4 Binary files /dev/null and b/docs/logo.png differ diff --git a/docs/testing.rst b/docs/testing.rst new file mode 100644 index 00000000..897fc5ca --- /dev/null +++ b/docs/testing.rst @@ -0,0 +1,105 @@ +.. _testing: + +======= +Testing +======= + +This document covers the tools to run tests and how to use them. + + +Django tests +============ + +Run the project tests by executing:: + + python src/manage.py test src --keepdb + +To measure coverage, use ``coverage run``:: + + coverage run src/manage.py test src --keepdb + +It may be convenient to add some aliases:: + + alias runtests='python src/manage.py test --keepdb' + runtests src + +and:: + + alias cov_runtests='coverage run src/manage.py test --keepdb' + cov_runtests src && chromium htmlcov/index.html + + +Jenkins +------- + +Run ``./bin/jenkins_django.sh`` to execute the tests for ``develop`` and ``master``. +This script runs the tests with ``--keepdb``. + +To run PR tests, run ``./bin/jenkins_django_pr.sh``. This script drops the test +database at the end, so it should be safe with different migrations between PR's. + + +SASS build - Jenkins +==================== + +There is a simple ``./bin/jenkins_sass.sh`` script that checks if the sass +compiles successfully. + + +Javascript tests +================ + +There are quite some options to run the Javascript tests. Karma is used as +test-runner, and you need to install it globally if you have never done so:: + + sudo npm install -g karma + +By default, the tests are run against Chrome/Chromium. To run +the tests, execute:: + + npm test + +If you want to target a single browser, you can run karma directly:: + + karma start karma.conf.js --single-run --browsers=PhantomJS + +Coverage reports can be found in ``build/reports/coverage``. + +To trigger a test run on file change (source file or test file), run:: + + karma start karma.conf.js --single-run=false --browsers=PhantomJS + + +Jenkins +------- + +On Jenkins, the tests are run against PhantomJS and Chrome. Therefore, ``xfvb`` +needs to be available. + +Run the tests by invoking ``./bin/jenkins_js.sh``. + + +Jenkins jobs +============ + +It is recommended to set up the following Jenkins jobs for a project: + +**master** branch +----------------- + +1. ``opendms-django``: backend tests, runs ``./bin/jenkins_django.sh``. +2. ``opendms-js``: frontend tests, runs ``./bin/jenkins_js.sh``. + +**develop** branch +------------------ + +1. ``opendms-django-develop``: backend tests, runs ``./bin/jenkins_django.sh``. +2. ``opendms-django-develop-js``: frontend tests, runs ``./bin/jenkins_js.sh``. + +pull requests +------------- +1. ``opendms-pr-django``: backend tests, runs ``./bin/jenkins_django_pr.sh``. +2. ``opendms-pr-js``: frontend tests, runs ``./bin/jenkins_js.sh``. +3. ``opendms-pr-sass``: checks that sass compiles, runs ``./bin/jenkins_sass.sh``. +4. ``opendms-pr-isort``: checks that imports are correctly + sorted, runs ``./bin/jenkins_isort.sh``. diff --git a/pyproject.toml b/pyproject.toml index 570775b9..aa14f2a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,55 @@ extend-select = [ "UP", # pyupgrade ] +ignore = [ + # Checks for assertRaises and pytest.raises context managers that catch Exception or BaseException. + "B017", + # Checks for useless expressions. + "B018", + # Checks for raise statements in exception handlers that lack a from clause. + "B904", + # Whitespace before ':' (conflicts with Black) + "E203", + # Checks for lines that exceed the specified maximum character length. + "E501", + # Do not assign a lambda expression + "E731", + # Name may be undefined from '*' import + "F405", + # Checks for CamelCase imports that are aliased to lowercase names + "N813", + # Checks for CamelCase imports that are aliased to constant-style names. + "N814", + # Checks for class variable names that follow the mixedCase convention + "N815", + # Exception name should be named with Error suffix + "N818", + # Checks for instance methods that use a name other than self for their first argument. + "N805", + # Checks for the use of non-lowercase variable names in functions + "N806", + # Checks for functions names that do not follow the snake_case naming convention. + "N802", + # Checks for module names that do not follow the snake_case naming convention or are otherwise invalid. + "N999", + # Checks for for loops that can be replaced by a list comprehension. + "PERF401", + # Checks for `if` statements that can be replaced with bool + "SIM103", + # Check for if-else-blocks that can be replaced with a ternary operator + "SIM108", + #Check for environment variables that are not capitalized. + "SIM112", + # Checks for nested if statements that can be collapsed into a single if statement + "SIM102", + # Use a single `with` statement with multiple contexts instead of nested `with` statements + "SIM117", + # Checks for str.format calls that can be replaced with f-strings. + "UP032", + # An undefined name is likely to raise NameError at runtime. + "F821", +] + [tool.ruff.lint.isort] combine-as-imports = true section-order = [ diff --git a/requirements/base.in b/requirements/base.in index 3bf694b0..a8a55c61 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,28 +1,12 @@ # Core python libraries Pillow # handle images -psycopg # database driver -python-dotenv # environment variables for secrets -# Framework libraries -django ~= 5.2 -django-admin-index -django-axes[ipware] django-hijack -django-redis -django-rosetta -maykin-2fa maykin-common[axes,cli,health-checks,mfa,otel] # other extras: pdf, vcr -mozilla-django-oidc-db josepy - +django-rosetta # API libraries -djangorestframework-camel-case -open-api-framework - -# WSGI servers & monitoring - production oriented -uwsgi -sentry-sdk # error monitoring -elastic-apm # Elastic APM integration +open-api-framework[cors,markup,geo,csp,commonground,inclusions,sanitization,server,redis,structlog] #postgres package psycopg2-binary diff --git a/requirements/base.txt b/requirements/base.txt index 514152e9..2cee64c8 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,24 +1,39 @@ # This file was autogenerated by uv via the following command: # ./bin/compile_dependencies.sh +amqp==5.3.1 + # via kombu annotated-doc==0.0.4 # via typer annotated-types==0.7.0 # via pydantic +ape-pie==0.2.0 + # via + # commonground-api-common + # notifications-api-common + # zgw-consumers asgiref==3.11.1 # via # django # django-axes + # django-cors-headers + # django-structlog attrs==25.4.0 # via # glom # jsonschema # referencing +billiard==4.2.4 + # via celery +bleach==6.3.0 + # via open-api-framework boltons==25.0.0 # via # face # glom cbor2==5.8.0 # via webauthn +celery==5.6.2 + # via notifications-api-common certifi==2026.1.4 # via # elastic-apm @@ -29,56 +44,89 @@ cffi==2.0.0 charset-normalizer==3.4.4 # via requests click==8.3.1 - # via typer + # via + # celery + # click-didyoumean + # click-plugins + # click-repl + # typer +click-didyoumean==0.3.1 + # via celery +click-plugins==1.1.1.2 + # via celery +click-repl==0.3.0 + # via celery +commonground-api-common==2.11.0 + # via open-api-framework cryptography==46.0.5 # via + # django-simple-certmanager # josepy # mozilla-django-oidc # pyopenssl # webauthn django==5.2.11 # via - # -r requirements/base.in + # commonground-api-common # django-admin-index # django-appconf # django-axes + # django-cors-headers + # django-csp # django-filter # django-formtools # django-health-check # django-hijack # django-jsonform # django-log-outgoing-requests + # django-markup # django-otp # django-phonenumber-field + # django-privates # django-redis + # django-relativedelta + # django-rest-framework-condition # django-rosetta + # django-sendfile2 # django-sessionprofile # django-setup-configuration + # django-simple-certmanager # django-solo + # django-structlog # django-two-factor-auth # django-upgrade-check # djangorestframework + # djangorestframework-gis + # djangorestframework-inclusions + # drf-nested-routers # drf-spectacular # drf-spectacular-sidecar # maykin-2fa # maykin-common # mozilla-django-oidc # mozilla-django-oidc-db + # notifications-api-common # open-api-framework + # zgw-consumers django-admin-index==4.0.0 # via - # -r requirements/base.in # maykin-common # open-api-framework django-appconf==1.2.0 # via django-log-outgoing-requests django-axes==8.3.1 # via - # -r requirements/base.in # maykin-common # open-api-framework -django-filter==25.1 +django-cors-headers==4.9.0 # via open-api-framework +django-csp==4.0 + # via open-api-framework +django-filter==25.1 + # via + # commonground-api-common + # djangorestframework-gis + # open-api-framework django-formtools==2.5.1 # via django-two-factor-auth django-health-check==4.0.0 @@ -86,13 +134,15 @@ django-health-check==4.0.0 django-hijack==3.7.6 # via -r requirements/base.in django-ipware==7.0.1 - # via django-axes + # via django-structlog django-jsonform==2.23.2 # via # mozilla-django-oidc-db # open-api-framework django-log-outgoing-requests==0.7.1 # via open-api-framework +django-markup==1.10 + # via open-api-framework django-ordered-model==3.7.4 # via django-admin-index django-otp==1.7.0 @@ -101,42 +151,73 @@ django-otp==1.7.0 # maykin-2fa django-phonenumber-field==8.4.0 # via django-two-factor-auth +django-privates==3.1.1 + # via django-simple-certmanager django-redis==6.0.0 - # via -r requirements/base.in + # via open-api-framework +django-relativedelta==2.0.0 + # via zgw-consumers +django-rest-framework-condition==0.1.1 + # via commonground-api-common django-rosetta==0.10.3 # via -r requirements/base.in +django-sendfile2==0.7.2 + # via django-privates django-sessionprofile==3.0.0 # via open-api-framework django-setup-configuration==0.11.0 # via open-api-framework +django-simple-certmanager==2.5.0 + # via zgw-consumers django-solo==2.5.1 - # via django-log-outgoing-requests + # via + # commonground-api-common + # django-log-outgoing-requests + # notifications-api-common + # zgw-consumers +django-structlog==10.0.0 + # via open-api-framework django-two-factor-auth==1.18.1 # via maykin-2fa django-upgrade-check==1.1.0 # via open-api-framework djangorestframework==3.16.1 # via + # commonground-api-common + # djangorestframework-gis + # djangorestframework-inclusions + # drf-nested-routers # drf-spectacular + # notifications-api-common # open-api-framework djangorestframework-camel-case==1.4.2 - # via -r requirements/base.in + # via + # commonground-api-common + # notifications-api-common +djangorestframework-gis==1.2.0 + # via open-api-framework +djangorestframework-inclusions==1.2.0 + # via open-api-framework dnspython==2.8.0 # via django-health-check docutils==0.22.4 # via django-setup-configuration +drf-nested-routers==0.95.0 + # via commonground-api-common drf-spectacular==0.29.0 - # via open-api-framework + # via + # commonground-api-common + # open-api-framework drf-spectacular-sidecar==2026.1.1 # via drf-spectacular ecs-logging==2.3.0 # via elastic-apm elastic-apm==6.25.0 - # via - # -r requirements/base.in - # open-api-framework + # via open-api-framework face==26.0.0 # via glom +furl==2.1.4 + # via ape-pie glom==25.12.0 # via mozilla-django-oidc-db googleapis-common-protos==1.72.0 @@ -151,17 +232,20 @@ importlib-metadata==8.7.1 # via opentelemetry-api inflection==0.5.1 # via drf-spectacular +iso639-lang==2.6.3 + # via commonground-api-common josepy==2.2.0 # via -r requirements/base.in jsonschema==4.26.0 # via drf-spectacular jsonschema-specifications==2025.9.1 # via jsonschema +kombu==5.6.2 + # via celery markdown-it-py==4.0.0 # via rich maykin-2fa==2.0.1 # via - # -r requirements/base.in # maykin-common # open-api-framework maykin-common==0.18.0 @@ -171,9 +255,9 @@ mdurl==0.1.2 mozilla-django-oidc==5.0.2 # via mozilla-django-oidc-db mozilla-django-oidc-db==1.1.1 - # via - # -r requirements/base.in - # open-api-framework + # via open-api-framework +notifications-api-common==0.10.1 + # via commonground-api-common open-api-framework==0.13.4 # via -r requirements/base.in opentelemetry-api==1.39.1 @@ -252,20 +336,27 @@ opentelemetry-util-http==0.60b1 # opentelemetry-instrumentation-django # opentelemetry-instrumentation-requests # opentelemetry-instrumentation-wsgi +orderedmultidict==1.0.2 + # via furl +oyaml==1.0 + # via commonground-api-common packaging==26.0 - # via opentelemetry-instrumentation + # via + # django-csp + # kombu + # opentelemetry-instrumentation pillow==12.1.1 # via -r requirements/base.in polib==1.2.0 # via django-rosetta +prompt-toolkit==3.0.52 + # via click-repl protobuf==6.33.5 # via # googleapis-common-protos # opentelemetry-proto psycopg==3.3.2 - # via - # -r requirements/base.in - # open-api-framework + # via open-api-framework psycopg-binary==3.3.2 # via psycopg psycopg2-binary==2.9.11 @@ -285,16 +376,22 @@ pydantic-settings==2.13.0 pygments==2.19.2 # via rich pyjwt==2.11.0 - # via mozilla-django-oidc + # via + # commonground-api-common + # mozilla-django-oidc + # zgw-consumers pyopenssl==25.3.0 # via webauthn +python-dateutil==2.9.0.post0 + # via + # celery + # django-relativedelta python-decouple==3.8 # via # maykin-common # open-api-framework python-dotenv==1.2.1 # via - # -r requirements/base.in # open-api-framework # pydantic-settings python-ipware==3.0.0 @@ -302,10 +399,11 @@ python-ipware==3.0.0 pyyaml==6.0.3 # via # drf-spectacular + # oyaml # pydantic-settings qrcode==8.2 # via django-two-factor-auth -redis==7.1.1 +redis==7.2.0 # via django-redis referencing==0.37.0 # via @@ -313,12 +411,15 @@ referencing==0.37.0 # jsonschema-specifications requests==2.32.5 # via + # ape-pie + # commonground-api-common # django-log-outgoing-requests # django-rosetta # maykin-common # mozilla-django-oidc # open-api-framework # opentelemetry-exporter-otlp-proto-http + # zgw-consumers rich==14.3.2 # via typer rpds-py==0.30.0 @@ -331,12 +432,21 @@ semantic-version==2.10.0 # via django-upgrade-check sentry-sdk==2.52.0 # via - # -r requirements/base.in + # commonground-api-common # open-api-framework shellingham==1.5.4 # via typer +six==1.17.0 + # via + # furl + # orderedmultidict + # python-dateutil sqlparse==0.5.5 # via django +structlog==25.5.0 + # via + # django-structlog + # open-api-framework typer==0.23.1 # via maykin-common typing-extensions==4.15.0 @@ -348,13 +458,21 @@ typing-extensions==4.15.0 # opentelemetry-exporter-otlp-proto-http # opentelemetry-sdk # opentelemetry-semantic-conventions + # psycopg # pydantic # pydantic-core + # pyopenssl + # referencing # typing-inspection + # zgw-consumers typing-inspection==0.4.2 # via # pydantic # pydantic-settings +tzdata==2025.3 + # via kombu +tzlocal==5.3.1 + # via celery uritemplate==4.2.0 # via drf-spectacular urllib3==2.6.3 @@ -363,14 +481,27 @@ urllib3==2.6.3 # requests # sentry-sdk uwsgi==2.0.31 - # via -r requirements/base.in + # via open-api-framework +vine==5.1.0 + # via + # amqp + # celery + # kombu +wcwidth==0.6.0 + # via prompt-toolkit webauthn==2.7.1 # via django-two-factor-auth +webencodings==0.5.1 + # via bleach wrapt==1.17.3 # via # elastic-apm # opentelemetry-instrumentation # opentelemetry-instrumentation-dbapi # opentelemetry-instrumentation-redis +zgw-consumers==1.2.0 + # via + # commonground-api-common + # notifications-api-common zipp==3.23.0 # via importlib-metadata diff --git a/requirements/ci.txt b/requirements/ci.txt index aebb2537..299691e9 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -1,5 +1,12 @@ # This file was autogenerated by uv via the following command: # ./bin/compile_dependencies.sh +alabaster==1.0.0 + # via sphinx +amqp==5.3.1 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # kombu annotated-doc==0.0.4 # via # -c requirements/base.txt @@ -10,12 +17,21 @@ annotated-types==0.7.0 # -c requirements/base.txt # -r requirements/base.txt # pydantic +ape-pie==0.2.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # commonground-api-common + # notifications-api-common + # zgw-consumers asgiref==3.11.1 # via # -c requirements/base.txt # -r requirements/base.txt # django # django-axes + # django-cors-headers + # django-structlog attrs==25.4.0 # via # -c requirements/base.txt @@ -23,8 +39,19 @@ attrs==25.4.0 # glom # jsonschema # referencing +babel==2.18.0 + # via sphinx beautifulsoup4==4.14.3 # via webtest +billiard==4.2.4 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # celery +bleach==6.3.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt boltons==25.0.0 # via # -c requirements/base.txt @@ -36,6 +63,11 @@ cbor2==5.8.0 # -c requirements/base.txt # -r requirements/base.txt # webauthn +celery==5.6.2 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # notifications-api-common certifi==2026.1.4 # via # -c requirements/base.txt @@ -57,13 +89,39 @@ click==8.3.1 # via # -c requirements/base.txt # -r requirements/base.txt + # celery + # click-didyoumean + # click-plugins + # click-repl # typer +click-didyoumean==0.3.1 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # celery +click-plugins==1.1.1.2 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # celery +click-repl==0.3.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # celery +commonground-api-common==2.11.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt +commonmark==0.9.1 + # via recommonmark coverage==7.13.4 # via -r requirements/test-tools.in cryptography==46.0.5 # via # -c requirements/base.txt # -r requirements/base.txt + # django-simple-certmanager # josepy # mozilla-django-oidc # pyopenssl @@ -74,32 +132,47 @@ django==5.2.11 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common # django-admin-index # django-appconf # django-axes + # django-cors-headers + # django-csp # django-filter # django-formtools # django-health-check # django-hijack # django-jsonform # django-log-outgoing-requests + # django-markup # django-otp # django-phonenumber-field + # django-privates # django-redis + # django-relativedelta + # django-rest-framework-condition # django-rosetta + # django-sendfile2 # django-sessionprofile # django-setup-configuration + # django-simple-certmanager # django-solo + # django-structlog # django-two-factor-auth # django-upgrade-check # djangorestframework + # djangorestframework-gis + # djangorestframework-inclusions + # drf-nested-routers # drf-spectacular # drf-spectacular-sidecar # maykin-2fa # maykin-common # mozilla-django-oidc # mozilla-django-oidc-db + # notifications-api-common # open-api-framework + # zgw-consumers django-admin-index==4.0.0 # via # -c requirements/base.txt @@ -115,10 +188,20 @@ django-axes==8.3.1 # -c requirements/base.txt # -r requirements/base.txt # open-api-framework +django-cors-headers==4.9.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt +django-csp==4.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt django-filter==25.1 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common + # djangorestframework-gis # open-api-framework django-formtools==2.5.1 # via @@ -137,6 +220,7 @@ django-ipware==7.0.1 # via # -c requirements/base.txt # -r requirements/base.txt + # django-structlog django-jsonform==2.23.2 # via # -c requirements/base.txt @@ -148,6 +232,10 @@ django-log-outgoing-requests==0.7.1 # -c requirements/base.txt # -r requirements/base.txt # open-api-framework +django-markup==1.10 + # via + # -c requirements/base.txt + # -r requirements/base.txt django-ordered-model==3.7.4 # via # -c requirements/base.txt @@ -164,14 +252,34 @@ django-phonenumber-field==8.4.0 # -c requirements/base.txt # -r requirements/base.txt # django-two-factor-auth +django-privates==3.1.1 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # django-simple-certmanager django-redis==6.0.0 # via # -c requirements/base.txt # -r requirements/base.txt +django-relativedelta==2.0.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # zgw-consumers +django-rest-framework-condition==0.1.1 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # commonground-api-common django-rosetta==0.10.3 # via # -c requirements/base.txt # -r requirements/base.txt +django-sendfile2==0.7.2 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # django-privates django-sessionprofile==3.0.0 # via # -c requirements/base.txt @@ -182,11 +290,23 @@ django-setup-configuration==0.11.0 # -c requirements/base.txt # -r requirements/base.txt # open-api-framework +django-simple-certmanager==2.5.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # zgw-consumers django-solo==2.5.1 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common # django-log-outgoing-requests + # notifications-api-common + # zgw-consumers +django-structlog==10.0.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt django-two-factor-auth==1.18.1 # via # -c requirements/base.txt @@ -203,12 +323,27 @@ djangorestframework==3.16.1 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common + # djangorestframework-gis + # djangorestframework-inclusions + # drf-nested-routers # drf-spectacular + # notifications-api-common # open-api-framework djangorestframework-camel-case==1.4.2 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common + # notifications-api-common +djangorestframework-gis==1.2.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt +djangorestframework-inclusions==1.2.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt dnspython==2.8.0 # via # -c requirements/base.txt @@ -219,10 +354,20 @@ docutils==0.22.4 # -c requirements/base.txt # -r requirements/base.txt # django-setup-configuration + # recommonmark + # sphinx + # sphinx-rtd-theme + # sphinx-tabs +drf-nested-routers==0.95.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # commonground-api-common drf-spectacular==0.29.0 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common # open-api-framework drf-spectacular-sidecar==2026.1.1 # via @@ -250,6 +395,11 @@ faker==40.4.0 # via factory-boy freezegun==1.5.5 # via -r requirements/test-tools.in +furl==2.1.4 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # ape-pie glom==25.12.0 # via # -c requirements/base.txt @@ -271,6 +421,8 @@ idna==3.11 # -c requirements/base.txt # -r requirements/base.txt # requests +imagesize==1.4.1 + # via sphinx importlib-metadata==8.7.1 # via # -c requirements/base.txt @@ -281,6 +433,13 @@ inflection==0.5.1 # -c requirements/base.txt # -r requirements/base.txt # drf-spectacular +iso639-lang==2.6.3 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # commonground-api-common +jinja2==3.1.6 + # via sphinx josepy==2.2.0 # via # -c requirements/base.txt @@ -295,15 +454,22 @@ jsonschema-specifications==2025.9.1 # -c requirements/base.txt # -r requirements/base.txt # jsonschema -legacy-cgi==2.6.4 - # via webob +kombu==5.6.2 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # celery lxml==6.0.2 # via pyquery +markdown==3.10.2 + # via sphinx-markdown-tables markdown-it-py==4.0.0 # via # -c requirements/base.txt # -r requirements/base.txt # rich +markupsafe==3.0.3 + # via jinja2 maykin-2fa==2.0.1 # via # -c requirements/base.txt @@ -328,6 +494,11 @@ mozilla-django-oidc-db==1.1.1 # -c requirements/base.txt # -r requirements/base.txt # open-api-framework +notifications-api-common==0.10.1 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # commonground-api-common open-api-framework==0.13.4 # via # -c requirements/base.txt @@ -446,11 +617,24 @@ opentelemetry-util-http==0.60b1 # opentelemetry-instrumentation-django # opentelemetry-instrumentation-requests # opentelemetry-instrumentation-wsgi +orderedmultidict==1.0.2 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # furl +oyaml==1.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # commonground-api-common packaging==26.0 # via # -c requirements/base.txt # -r requirements/base.txt + # django-csp + # kombu # opentelemetry-instrumentation + # sphinx pillow==12.1.1 # via # -c requirements/base.txt @@ -460,6 +644,11 @@ polib==1.2.0 # -c requirements/base.txt # -r requirements/base.txt # django-rosetta +prompt-toolkit==3.0.52 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # click-repl protobuf==6.33.5 # via # -c requirements/base.txt @@ -511,11 +700,15 @@ pygments==2.19.2 # -c requirements/base.txt # -r requirements/base.txt # rich + # sphinx + # sphinx-tabs pyjwt==2.11.0 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common # mozilla-django-oidc + # zgw-consumers pyopenssl==25.3.0 # via # -c requirements/base.txt @@ -524,7 +717,12 @@ pyopenssl==25.3.0 pyquery==2.0.1 # via -r requirements/test-tools.in python-dateutil==2.9.0.post0 - # via freezegun + # via + # -c requirements/base.txt + # -r requirements/base.txt + # celery + # django-relativedelta + # freezegun python-decouple==3.8 # via # -c requirements/base.txt @@ -547,13 +745,16 @@ pyyaml==6.0.3 # -c requirements/base.txt # -r requirements/base.txt # drf-spectacular + # oyaml # pydantic-settings qrcode==8.2 # via # -c requirements/base.txt # -r requirements/base.txt # django-two-factor-auth -redis==7.1.1 +recommonmark==0.7.1 + # via -r requirements/docs.in +redis==7.2.0 # via # -c requirements/base.txt # -r requirements/base.txt @@ -568,16 +769,22 @@ requests==2.32.5 # via # -c requirements/base.txt # -r requirements/base.txt + # ape-pie + # commonground-api-common # django-log-outgoing-requests # django-rosetta # mozilla-django-oidc # open-api-framework # opentelemetry-exporter-otlp-proto-http + # sphinx + # zgw-consumers rich==14.3.2 # via # -c requirements/base.txt # -r requirements/base.txt # typer +roman-numerals==4.1.0 + # via sphinx rpds-py==0.30.0 # via # -c requirements/base.txt @@ -600,6 +807,7 @@ sentry-sdk==2.52.0 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common # open-api-framework shellingham==1.5.4 # via @@ -607,14 +815,53 @@ shellingham==1.5.4 # -r requirements/base.txt # typer six==1.17.0 - # via python-dateutil + # via + # -c requirements/base.txt + # -r requirements/base.txt + # furl + # orderedmultidict + # python-dateutil +snowballstemmer==3.0.1 + # via sphinx soupsieve==2.8.3 # via beautifulsoup4 +sphinx==9.1.0 + # via + # -r requirements/docs.in + # recommonmark + # sphinx-rtd-theme + # sphinx-tabs + # sphinxcontrib-jquery +sphinx-markdown-tables==0.0.17 + # via -r requirements/docs.in +sphinx-rtd-theme==3.1.0 + # via -r requirements/docs.in +sphinx-tabs==3.4.7 + # via -r requirements/docs.in +sphinxcontrib-applehelp==2.0.0 + # via sphinx +sphinxcontrib-devhelp==2.0.0 + # via sphinx +sphinxcontrib-htmlhelp==2.1.0 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==2.0.0 + # via sphinx +sphinxcontrib-serializinghtml==2.0.0 + # via sphinx sqlparse==0.5.5 # via # -c requirements/base.txt # -r requirements/base.txt # django +structlog==25.5.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # django-structlog tblib==3.2.2 # via -r requirements/test-tools.in typer==0.23.1 @@ -633,15 +880,29 @@ typing-extensions==4.15.0 # opentelemetry-exporter-otlp-proto-http # opentelemetry-sdk # opentelemetry-semantic-conventions + # psycopg # pydantic # pydantic-core + # pyopenssl + # referencing # typing-inspection + # zgw-consumers typing-inspection==0.4.2 # via # -c requirements/base.txt # -r requirements/base.txt # pydantic # pydantic-settings +tzdata==2025.3 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # kombu +tzlocal==5.3.1 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # celery uritemplate==4.2.0 # via # -c requirements/base.txt @@ -658,13 +919,30 @@ uwsgi==2.0.31 # via # -c requirements/base.txt # -r requirements/base.txt +vine==5.1.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # amqp + # celery + # kombu waitress==3.0.2 # via webtest +wcwidth==0.6.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # prompt-toolkit webauthn==2.7.1 # via # -c requirements/base.txt # -r requirements/base.txt # django-two-factor-auth +webencodings==0.5.1 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # bleach webob==1.8.9 # via webtest webtest==3.0.7 @@ -677,6 +955,12 @@ wrapt==1.17.3 # opentelemetry-instrumentation # opentelemetry-instrumentation-dbapi # opentelemetry-instrumentation-redis +zgw-consumers==1.2.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # commonground-api-common + # notifications-api-common zipp==3.23.0 # via # -c requirements/base.txt diff --git a/requirements/dev.txt b/requirements/dev.txt index ebefe585..15a75086 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,7 +1,15 @@ # This file was autogenerated by uv via the following command: # ./bin/compile_dependencies.sh alabaster==1.0.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx +amqp==5.3.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # kombu annotated-doc==0.0.4 # via # -c requirements/ci.txt @@ -14,12 +22,21 @@ annotated-types==0.7.0 # pydantic anyio==4.12.1 # via httpx +ape-pie==0.2.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # commonground-api-common + # notifications-api-common + # zgw-consumers asgiref==3.11.1 # via # -c requirements/ci.txt # -r requirements/ci.txt # django # django-axes + # django-cors-headers + # django-structlog attrs==25.4.0 # via # -c requirements/ci.txt @@ -28,12 +45,24 @@ attrs==25.4.0 # jsonschema # referencing babel==2.18.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx beautifulsoup4==4.14.3 # via # -c requirements/ci.txt # -r requirements/ci.txt # webtest +billiard==4.2.4 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # celery +bleach==6.3.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt boltons==25.0.0 # via # -c requirements/ci.txt @@ -49,6 +78,11 @@ cbor2==5.8.0 # -c requirements/ci.txt # -r requirements/ci.txt # webauthn +celery==5.6.2 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # notifications-api-common certifi==2026.1.4 # via # -c requirements/ci.txt @@ -73,8 +107,36 @@ click==8.3.1 # -c requirements/ci.txt # -r requirements/ci.txt # bump-my-version + # celery + # click-didyoumean + # click-plugins + # click-repl # rich-click # typer +click-didyoumean==0.3.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # celery +click-plugins==1.1.1.2 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # celery +click-repl==0.3.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # celery +commonground-api-common==2.11.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt +commonmark==0.9.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # recommonmark coverage==7.13.4 # via # -c requirements/ci.txt @@ -83,6 +145,7 @@ cryptography==46.0.5 # via # -c requirements/ci.txt # -r requirements/ci.txt + # django-simple-certmanager # josepy # mozilla-django-oidc # pyopenssl @@ -96,9 +159,12 @@ django==5.2.11 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common # django-admin-index # django-appconf # django-axes + # django-cors-headers + # django-csp # django-debug-toolbar # django-extensions # django-filter @@ -107,23 +173,35 @@ django==5.2.11 # django-hijack # django-jsonform # django-log-outgoing-requests + # django-markup # django-otp # django-phonenumber-field + # django-privates # django-redis + # django-relativedelta + # django-rest-framework-condition # django-rosetta + # django-sendfile2 # django-sessionprofile # django-setup-configuration + # django-simple-certmanager # django-solo + # django-structlog # django-two-factor-auth # django-upgrade-check # djangorestframework + # djangorestframework-gis + # djangorestframework-inclusions + # drf-nested-routers # drf-spectacular # drf-spectacular-sidecar # maykin-2fa # maykin-common # mozilla-django-oidc # mozilla-django-oidc-db + # notifications-api-common # open-api-framework + # zgw-consumers django-admin-index==4.0.0 # via # -c requirements/ci.txt @@ -139,6 +217,14 @@ django-axes==8.3.1 # -c requirements/ci.txt # -r requirements/ci.txt # open-api-framework +django-cors-headers==4.9.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt +django-csp==4.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt django-debug-toolbar==6.2.0 # via -r requirements/dev.in django-extensions==4.1 @@ -147,6 +233,8 @@ django-filter==25.1 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common + # djangorestframework-gis # open-api-framework django-formtools==2.5.1 # via @@ -165,6 +253,7 @@ django-ipware==7.0.1 # via # -c requirements/ci.txt # -r requirements/ci.txt + # django-structlog django-jsonform==2.23.2 # via # -c requirements/ci.txt @@ -176,6 +265,10 @@ django-log-outgoing-requests==0.7.1 # -c requirements/ci.txt # -r requirements/ci.txt # open-api-framework +django-markup==1.10 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt django-ordered-model==3.7.4 # via # -c requirements/ci.txt @@ -192,14 +285,34 @@ django-phonenumber-field==8.4.0 # -c requirements/ci.txt # -r requirements/ci.txt # django-two-factor-auth +django-privates==3.1.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # django-simple-certmanager django-redis==6.0.0 # via # -c requirements/ci.txt # -r requirements/ci.txt +django-relativedelta==2.0.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # zgw-consumers +django-rest-framework-condition==0.1.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # commonground-api-common django-rosetta==0.10.3 # via # -c requirements/ci.txt # -r requirements/ci.txt +django-sendfile2==0.7.2 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # django-privates django-sessionprofile==3.0.0 # via # -c requirements/ci.txt @@ -210,11 +323,23 @@ django-setup-configuration==0.11.0 # -c requirements/ci.txt # -r requirements/ci.txt # open-api-framework +django-simple-certmanager==2.5.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # zgw-consumers django-solo==2.5.1 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common # django-log-outgoing-requests + # notifications-api-common + # zgw-consumers +django-structlog==10.0.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt django-two-factor-auth==1.18.1 # via # -c requirements/ci.txt @@ -233,12 +358,27 @@ djangorestframework==3.16.1 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common + # djangorestframework-gis + # djangorestframework-inclusions + # drf-nested-routers # drf-spectacular + # notifications-api-common # open-api-framework djangorestframework-camel-case==1.4.2 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common + # notifications-api-common +djangorestframework-gis==1.2.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt +djangorestframework-inclusions==1.2.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt dnspython==2.8.0 # via # -c requirements/ci.txt @@ -249,12 +389,20 @@ docutils==0.22.4 # -c requirements/ci.txt # -r requirements/ci.txt # django-setup-configuration + # recommonmark # sphinx # sphinx-rtd-theme + # sphinx-tabs +drf-nested-routers==0.95.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # commonground-api-common drf-spectacular==0.29.0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common # open-api-framework drf-spectacular-sidecar==2026.1.1 # via @@ -289,6 +437,11 @@ freezegun==1.5.5 # via # -c requirements/ci.txt # -r requirements/ci.txt +furl==2.1.4 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # ape-pie gitdb==4.0.12 # via gitpython gitpython==3.1.46 @@ -323,7 +476,10 @@ idna==3.11 # httpx # requests imagesize==1.4.1 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx importlib-metadata==8.7.1 # via # -c requirements/ci.txt @@ -334,8 +490,16 @@ inflection==0.5.1 # -c requirements/ci.txt # -r requirements/ci.txt # drf-spectacular +iso639-lang==2.6.3 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # commonground-api-common jinja2==3.1.6 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx josepy==2.2.0 # via # -c requirements/ci.txt @@ -350,23 +514,31 @@ jsonschema-specifications==2025.9.1 # -c requirements/ci.txt # -r requirements/ci.txt # jsonschema -legacy-cgi==2.6.4 +kombu==5.6.2 # via # -c requirements/ci.txt # -r requirements/ci.txt - # webob + # celery lxml==6.0.2 # via # -c requirements/ci.txt # -r requirements/ci.txt # pyquery +markdown==3.10.2 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx-markdown-tables markdown-it-py==4.0.0 # via # -c requirements/ci.txt # -r requirements/ci.txt # rich markupsafe==3.0.3 - # via jinja2 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # jinja2 maykin-2fa==2.0.1 # via # -c requirements/ci.txt @@ -391,6 +563,11 @@ mozilla-django-oidc-db==1.1.1 # -c requirements/ci.txt # -r requirements/ci.txt # open-api-framework +notifications-api-common==0.10.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # commonground-api-common open-api-framework==0.13.4 # via # -c requirements/ci.txt @@ -509,10 +686,22 @@ opentelemetry-util-http==0.60b1 # opentelemetry-instrumentation-django # opentelemetry-instrumentation-requests # opentelemetry-instrumentation-wsgi +orderedmultidict==1.0.2 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # furl +oyaml==1.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # commonground-api-common packaging==26.0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # django-csp + # kombu # opentelemetry-instrumentation # sphinx pillow==12.1.1 @@ -525,7 +714,11 @@ polib==1.2.0 # -r requirements/ci.txt # django-rosetta prompt-toolkit==3.0.52 - # via questionary + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # click-repl + # questionary protobuf==6.33.5 # via # -c requirements/ci.txt @@ -580,11 +773,14 @@ pygments==2.19.2 # -r requirements/ci.txt # rich # sphinx + # sphinx-tabs pyjwt==2.11.0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common # mozilla-django-oidc + # zgw-consumers pyopenssl==25.3.0 # via # -c requirements/ci.txt @@ -598,6 +794,8 @@ python-dateutil==2.9.0.post0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # celery + # django-relativedelta # freezegun python-decouple==3.8 # via @@ -621,6 +819,7 @@ pyyaml==6.0.3 # -c requirements/ci.txt # -r requirements/ci.txt # drf-spectacular + # oyaml # pydantic-settings qrcode==8.2 # via @@ -629,7 +828,11 @@ qrcode==8.2 # django-two-factor-auth questionary==2.1.1 # via bump-my-version -redis==7.1.1 +recommonmark==0.7.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt +redis==7.2.0 # via # -c requirements/ci.txt # -r requirements/ci.txt @@ -644,12 +847,15 @@ requests==2.32.5 # via # -c requirements/ci.txt # -r requirements/ci.txt + # ape-pie + # commonground-api-common # django-log-outgoing-requests # django-rosetta # mozilla-django-oidc # open-api-framework # opentelemetry-exporter-otlp-proto-http # sphinx + # zgw-consumers rich==14.3.2 # via # -c requirements/ci.txt @@ -660,7 +866,10 @@ rich==14.3.2 rich-click==1.9.7 # via bump-my-version roman-numerals==4.1.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx rpds-py==0.30.0 # via # -c requirements/ci.txt @@ -685,6 +894,7 @@ sentry-sdk==2.52.0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common # open-api-framework shellingham==1.5.4 # via @@ -695,11 +905,16 @@ six==1.17.0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # furl + # orderedmultidict # python-dateutil smmap==5.0.2 # via gitdb snowballstemmer==3.0.1 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx soupsieve==2.8.3 # via # -c requirements/ci.txt @@ -707,31 +922,72 @@ soupsieve==2.8.3 # beautifulsoup4 sphinx==9.1.0 # via + # -c requirements/ci.txt + # -r requirements/ci.txt # -r requirements/dev.in + # recommonmark # sphinx-rtd-theme + # sphinx-tabs # sphinxcontrib-jquery +sphinx-markdown-tables==0.0.17 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt sphinx-rtd-theme==3.1.0 - # via -r requirements/dev.in + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # -r requirements/dev.in +sphinx-tabs==3.4.7 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt sphinxcontrib-applehelp==2.0.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx sphinxcontrib-devhelp==2.0.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx sphinxcontrib-htmlhelp==2.1.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx sphinxcontrib-jquery==4.1 - # via sphinx-rtd-theme + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx sphinxcontrib-qthelp==2.0.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx sphinxcontrib-serializinghtml==2.0.0 - # via sphinx + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # sphinx sqlparse==0.5.5 # via # -c requirements/ci.txt # -r requirements/ci.txt # django # django-debug-toolbar +structlog==25.5.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # django-structlog tblib==3.2.2 # via # -c requirements/ci.txt @@ -746,6 +1002,7 @@ typing-extensions==4.15.0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # anyio # beautifulsoup4 # grpcio # mozilla-django-oidc-db @@ -754,15 +1011,29 @@ typing-extensions==4.15.0 # opentelemetry-exporter-otlp-proto-http # opentelemetry-sdk # opentelemetry-semantic-conventions + # psycopg # pydantic # pydantic-core + # pyopenssl + # referencing # typing-inspection + # zgw-consumers typing-inspection==0.4.2 # via # -c requirements/ci.txt # -r requirements/ci.txt # pydantic # pydantic-settings +tzdata==2025.3 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # kombu +tzlocal==5.3.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # celery uritemplate==4.2.0 # via # -c requirements/ci.txt @@ -779,6 +1050,13 @@ uwsgi==2.0.31 # via # -c requirements/ci.txt # -r requirements/ci.txt +vine==5.1.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # amqp + # celery + # kombu waitress==3.0.2 # via # -c requirements/ci.txt @@ -787,12 +1065,20 @@ waitress==3.0.2 wcmatch==10.1 # via bump-my-version wcwidth==0.6.0 - # via prompt-toolkit + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # prompt-toolkit webauthn==2.7.1 # via # -c requirements/ci.txt # -r requirements/ci.txt # django-two-factor-auth +webencodings==0.5.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # bleach webob==1.8.9 # via # -c requirements/ci.txt @@ -811,6 +1097,12 @@ wrapt==1.17.3 # opentelemetry-instrumentation # opentelemetry-instrumentation-dbapi # opentelemetry-instrumentation-redis +zgw-consumers==1.2.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # commonground-api-common + # notifications-api-common zipp==3.23.0 # via # -c requirements/ci.txt diff --git a/requirements/docs.in b/requirements/docs.in new file mode 100644 index 00000000..23f29dde --- /dev/null +++ b/requirements/docs.in @@ -0,0 +1,9 @@ +-c base.txt +-r base.txt + +# Documentation +sphinx +sphinx_rtd_theme +recommonmark +sphinx-markdown-tables +sphinx-tabs diff --git a/src/opendms/accounts/tests/test_password_reset_view.py b/src/opendms/accounts/tests/test_password_reset_view.py deleted file mode 100644 index 29ff3b4d..00000000 --- a/src/opendms/accounts/tests/test_password_reset_view.py +++ /dev/null @@ -1,13 +0,0 @@ -from django.test import TestCase -from django.urls import reverse - - -class PasswordResetViewTests(TestCase): - def test_user_cant_access_the_password_reset_view_more_than_5_times(self): - url = reverse("admin_password_reset") - - for _ in range(5): - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - response = self.client.get(url) - self.assertEqual(response.status_code, 429) diff --git a/src/opendms/accounts/views/__init__.py b/src/opendms/accounts/views/__init__.py deleted file mode 100644 index 5b0ea015..00000000 --- a/src/opendms/accounts/views/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .csrf import csrf_failure # noqa diff --git a/src/opendms/accounts/views/csrf.py b/src/opendms/accounts/views/csrf.py deleted file mode 100644 index 5cfa8bd4..00000000 --- a/src/opendms/accounts/views/csrf.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.conf import settings -from django.http import HttpResponseRedirect -from django.views.csrf import ( - CSRF_FAILURE_TEMPLATE_NAME, - csrf_failure as original_csrf_failure, -) - - -def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME): - """ - Catch CSRF failure when tryin to login a second time, when already logged - in, by redirecting to the LOGIN_REDIRECT_URL. - """ - if request.path in settings.LOGIN_URLS and request.user.is_authenticated: - return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL) - return original_csrf_failure(request, reason=reason, template_name=template_name) diff --git a/src/opendms/accounts/views/password_reset.py b/src/opendms/accounts/views/password_reset.py deleted file mode 100644 index d4ab2fb9..00000000 --- a/src/opendms/accounts/views/password_reset.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.contrib.auth import views as auth_views - -from maykin_common.throttling import IPThrottleMixin - - -class PasswordResetView(IPThrottleMixin, auth_views.PasswordResetView): - throttle_name = "password-reset" - throttle_visits = 5 - throttle_period = 60 - throttle_methods = ("get",) diff --git a/src/opendms/conf/base.py b/src/opendms/conf/base.py index 4d460a07..3dd8c385 100644 --- a/src/opendms/conf/base.py +++ b/src/opendms/conf/base.py @@ -1,9 +1,12 @@ -# ruff: noqa: F403,F405 -from maykin_common.config import config -from maykin_common.health_checks import ( - default_health_check_apps, -) +import os + +os.environ["_USE_STRUCTLOG"] = "True" + +from pathlib import Path + +from maykin_common.health_checks import default_health_check_apps from open_api_framework.conf.base import * # noqa +from open_api_framework.conf.utils import config # noqa # APPLICATIONS enabled for this project # @@ -20,64 +23,18 @@ "opendms.frontend", ] -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - # 'django.middleware.locale.LocaleMiddleware', - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "maykin_2fa.middleware.OTPMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", - "hijack.middleware.HijackUserMiddleware", - "djangorestframework_camel_case.middleware.CamelCaseMiddleWare", - # should be last according to docs - "axes.middleware.AxesMiddleware", -] - -ROOT_URLCONF = "opendms.urls" - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [ - DJANGO_PROJECT_DIR / "templates", - DJANGO_PROJECT_DIR / "frontend/dist", - ], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - "opendms.utils.context_processors.settings", - ], - }, - }, -] - - # Additional locations of static files -STATICFILES_DIRS = [ - DJANGO_PROJECT_DIR / "static", - DJANGO_PROJECT_DIR / "frontend/dist/static", -] - -LOGIN_URL = reverse_lazy("admin:login") +STATICFILES_DIRS += [Path(DJANGO_PROJECT_DIR) / "frontend/dist/static"] # # SECURITY settings # - -CSRF_FAILURE_VIEW = "opendms.accounts.views.csrf_failure" +CSRF_FAILURE_VIEW = "maykin_common.views.csrf_failure" # # FIXTURES # - -FIXTURE_DIRS = (DJANGO_PROJECT_DIR / "fixtures",) +FIXTURE_DIRS = (Path(DJANGO_PROJECT_DIR) / "fixtures",) # # Custom settings @@ -85,10 +42,26 @@ PROJECT_NAME = "Open DMS" # Displaying environment information -ENVIRONMENT_LABEL = config("ENVIRONMENT_LABEL", default=ENVIRONMENT) -ENVIRONMENT_BACKGROUND_COLOR = config("ENVIRONMENT_BACKGROUND_COLOR", default="orange") -ENVIRONMENT_FOREGROUND_COLOR = config("ENVIRONMENT_FOREGROUND_COLOR", default="black") -SHOW_ENVIRONMENT = config("SHOW_ENVIRONMENT", default=True) +ENVIRONMENT_LABEL = config( + "ENVIRONMENT_LABEL", + default=ENVIRONMENT, + add_to_docs=False, +) +ENVIRONMENT_BACKGROUND_COLOR = config( + "ENVIRONMENT_BACKGROUND_COLOR", + default="orange", + add_to_docs=False, +) +ENVIRONMENT_FOREGROUND_COLOR = config( + "ENVIRONMENT_FOREGROUND_COLOR", + default="black", + add_to_docs=False, +) +SHOW_ENVIRONMENT = config( + "SHOW_ENVIRONMENT", + default=True, + add_to_docs=False, +) # This setting is used by the csrf_failure view (accounts app). # You can specify any path that should match the request.path @@ -127,13 +100,28 @@ # # DJANGO REST FRAMEWORK # -ENABLE_THROTTLING = config("ENABLE_THROTTLING", default=True) - +ENABLE_THROTTLING = config( + "ENABLE_THROTTLING", + default=True, + add_to_docs=False, +) throttle_rate_anon = ( - config("THROTTLE_RATE_ANON", default="2500/hour") if ENABLE_THROTTLING else None + config( + "THROTTLE_RATE_ANON", + default="2500/hour", + add_to_docs=False, + ) + if ENABLE_THROTTLING + else None ) throttle_rate_user = ( - config("THROTTLE_RATE_USER", default="15000/hour") if ENABLE_THROTTLING else None + config( + "THROTTLE_RATE_USER", + default="15000/hour", + add_to_docs=False, + ) + if ENABLE_THROTTLING + else None ) REST_FRAMEWORK = { @@ -163,13 +151,6 @@ "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", } -# Subpath (optional) -# This environment variable can be configured during deployment. -SUBPATH = config("SUBPATH", default="") -if SUBPATH: - SUBPATH = f"/{SUBPATH.strip('/')}" - - # # SPECTACULAR - OpenAPI schema generation # diff --git a/src/opendms/conf/ci.py b/src/opendms/conf/ci.py index daccf13a..fab8ec1c 100644 --- a/src/opendms/conf/ci.py +++ b/src/opendms/conf/ci.py @@ -1,36 +1,44 @@ +""" +Continuous integration settings module. +""" + import os import warnings -os.environ.setdefault("DEBUG", "yes") -os.environ.setdefault("ALLOWED_HOSTS", "*") -os.environ.setdefault( - "SECRET_KEY", - "django-insecure-kex=ipoau_q(o_w=6bd8q6_sb2#xgkdbknq4m&hl2jtx(7#$n_", -) -os.environ.setdefault("IS_HTTPS", "no") -os.environ.setdefault("VERSION_TAG", "dev") +# Importing the idna module has an IO side-effect to load the data, which is a rather +# big file. Pre-loading this in the settings file populates the python module cache, +# preventing flakiness in hypothesis tests that hit this code path. +import idna # noqa: F401 +from open_api_framework.conf.utils import mute_logging -os.environ.setdefault("DB_NAME", "opendms") -os.environ.setdefault("DB_USER", "opendms") -os.environ.setdefault("DB_PASSWORD", "opendms") - -os.environ.setdefault("ENVIRONMENT", "development") +os.environ.setdefault("IS_HTTPS", "no") +os.environ.setdefault("SECRET_KEY", "dummy") +# Do not log requests in CI/tests: +# +# * overhead making tests slower +# * it conflicts with SimpleTestCase in some cases when the run-time configuration is +# looked up from the django-solo model +os.environ.setdefault("LOG_REQUESTS", "no") os.environ.setdefault("OTEL_SDK_DISABLED", "true") +os.environ.setdefault("OTEL_SERVICE_NAME", "opendms-ci") from .base import * # noqa isort:skip -from .base import CACHES CACHES.update( { - "default": { - "BACKEND": "django.core.cache.backends.locmem.LocMemCache", - "LOCATION": "default", - }, + "default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, # See: https://github.com/jazzband/django-axes/blob/master/docs/configuration.rst#cache-problems "axes": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"}, + "oidc": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, } ) +# shut up logging +mute_logging(LOGGING) + +# don't spend time on password hashing in tests/user factories +PASSWORD_HASHERS = ["django.contrib.auth.hashers.PBKDF2PasswordHasher"] + ENVIRONMENT = "CI" @@ -47,3 +55,5 @@ RuntimeWarning, r"django\.db\.models\.fields", ) + +NOTIFICATIONS_DISABLED = True diff --git a/src/opendms/conf/dev.py b/src/opendms/conf/dev.py index 517c265c..15f6c62c 100644 --- a/src/opendms/conf/dev.py +++ b/src/opendms/conf/dev.py @@ -1,9 +1,6 @@ -# ruff: noqa: F403,F405 import os import warnings -from maykin_common.config import config - os.environ.setdefault("DEBUG", "yes") os.environ.setdefault("ALLOWED_HOSTS", "*") os.environ.setdefault( @@ -18,7 +15,15 @@ os.environ.setdefault("DB_PASSWORD", "opendms") os.environ.setdefault("ENVIRONMENT", "development") +os.environ.setdefault("DISABLE_2FA", "yes") +os.environ.setdefault("LOG_FORMAT_CONSOLE", "plain_console") + +os.environ.setdefault("RELEASE", "dev") +os.environ.setdefault("LOG_REQUESTS", "no") + os.environ.setdefault("OTEL_SDK_DISABLED", "true") +os.environ.setdefault("OTEL_EXPORTER_OTLP_METRICS_INSECURE", "true") + from .base import * # noqa isort:skip @@ -35,58 +40,75 @@ "opendms": { "handlers": ["console"], "level": "DEBUG", - "propagate": True, + "propagate": False, }, "django": { "handlers": ["console"], "level": "DEBUG", - "propagate": True, + "propagate": False, }, "django.db.backends": { - "handlers": ["django"], + "handlers": ["json_file"], "level": "DEBUG", "propagate": False, }, "performance": { "handlers": ["console"], "level": "INFO", - "propagate": True, + "propagate": False, }, # # See: https://code.djangoproject.com/ticket/30554 # Autoreload logs excessively, turn it down a bit. # "django.utils.autoreload": { - "handlers": ["django"], + "handlers": ["console"], "level": "INFO", "propagate": False, }, } ) -SESSION_ENGINE = "django.contrib.sessions.backends.db" - # in memory cache and django-axes don't get along. # https://django-axes.readthedocs.io/en/latest/configuration.html#known-configuration-problems CACHES = { "default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, "axes": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"}, + "oidc": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, } # # Library settings # +# Django extensions +INSTALLED_APPS += ["django_extensions"] + ELASTIC_APM["DEBUG"] = True # Django debug toolbar INSTALLED_APPS += ["debug_toolbar"] -MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE -INTERNAL_IPS = ("127.0.0.1",) +MIDDLEWARE += [ + "debug_toolbar.middleware.DebugToolbarMiddleware", +] -# None of the authentication backends require two-factor authentication. -if config("DISABLE_2FA", default=True): - MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = AUTHENTICATION_BACKENDS +INTERNAL_IPS = ("127.0.0.1",) +DEBUG_TOOLBAR_CONFIG = {"INTERCEPT_REDIRECTS": False} +DEBUG_TOOLBAR_PANELS = [ + "debug_toolbar.panels.versions.VersionsPanel", + "debug_toolbar.panels.timer.TimerPanel", + "debug_toolbar.panels.settings.SettingsPanel", + "debug_toolbar.panels.headers.HeadersPanel", + "debug_toolbar.panels.request.RequestPanel", + "debug_toolbar.panels.sql.SQLPanel", + "debug_toolbar.panels.staticfiles.StaticFilesPanel", + "debug_toolbar.panels.templates.TemplatesPanel", + "debug_toolbar.panels.cache.CachePanel", + "debug_toolbar.panels.signals.SignalsPanel", + "debug_toolbar.panels.logging.LoggingPanel", + "debug_toolbar.panels.redirects.RedirectsPanel", + "debug_toolbar.panels.profiling.ProfilingPanel", +] # THOU SHALT NOT USE NAIVE DATETIMES warnings.filterwarnings( @@ -97,7 +119,7 @@ ) # Override settings with local settings. -try: +try: # noqa: SIM105 from .local import * # noqa except ImportError: pass diff --git a/src/opendms/conf/jenkins.py b/src/opendms/conf/jenkins.py index d6a2f8a3..083aeba8 100644 --- a/src/opendms/conf/jenkins.py +++ b/src/opendms/conf/jenkins.py @@ -59,9 +59,6 @@ def get_db_name(prefix): ELASTIC_APM["DEBUG"] = True -# disable 2 FA in tests -MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = AUTHENTICATION_BACKENDS - # THOU SHALT NOT USE NAIVE DATETIMES warnings.filterwarnings( "error", diff --git a/src/opendms/conf/production.py b/src/opendms/conf/production.py index ffdfb9ba..02b3a24e 100644 --- a/src/opendms/conf/production.py +++ b/src/opendms/conf/production.py @@ -66,6 +66,7 @@ "elasticapm.contrib.django", ] -if SUBPATH and SUBPATH != "/": - STATIC_URL = f"{SUBPATH}{STATIC_URL}" - MEDIA_URL = f"{SUBPATH}{MEDIA_URL}" +# Deal with being hosted on a subpath +if subpath and subpath != "/": + STATIC_URL = f"{subpath}{STATIC_URL}" + MEDIA_URL = f"{subpath}{MEDIA_URL}" diff --git a/src/opendms/urls.py b/src/opendms/urls.py index 481eee04..22d020a9 100644 --- a/src/opendms/urls.py +++ b/src/opendms/urls.py @@ -9,10 +9,9 @@ from maykin_2fa import monkeypatch_admin from maykin_2fa.urls import urlpatterns, webauthn_urlpatterns +from maykin_common.accounts.views import PasswordResetView from mozilla_django_oidc_db.views import AdminLoginFailure -from opendms.accounts.views.password_reset import PasswordResetView - # Configure admin monkeypatch_admin()