From 6712f4aea83e65380e86ad379fdf0f02bacfa8ec Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Sun, 29 Sep 2024 22:50:58 -0400 Subject: [PATCH 1/9] chore: Rename cove_project to core, like in handbook --- .github/workflows/ci.yml | 2 +- {cove_project => core}/__init__.py | 0 {cove_project => core}/context_processors.py | 0 {cove_project => core}/settings.py | 0 {cove_project => core}/templates/terms.html | 0 {cove_project => core}/urls.py | 0 {cove_project => core}/wsgi.py | 4 ++-- manage.py | 2 +- pyproject.toml | 2 +- 9 files changed, 5 insertions(+), 5 deletions(-) rename {cove_project => core}/__init__.py (100%) rename {cove_project => core}/context_processors.py (100%) rename {cove_project => core}/settings.py (100%) rename {cove_project => core}/templates/terms.html (100%) rename {cove_project => core}/urls.py (100%) rename {cove_project => core}/wsgi.py (72%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 713d465..7132bdf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,5 +23,5 @@ jobs: ./manage.py migrate ./manage.py makemigrations --check --dry-run ./manage.py check --fail-level WARNING - coverage run --source=cove_oc4ids,cove_project -m pytest -W error + coverage run --source=core,cove_oc4ids -m pytest -W error - uses: coverallsapp/github-action@v2 diff --git a/cove_project/__init__.py b/core/__init__.py similarity index 100% rename from cove_project/__init__.py rename to core/__init__.py diff --git a/cove_project/context_processors.py b/core/context_processors.py similarity index 100% rename from cove_project/context_processors.py rename to core/context_processors.py diff --git a/cove_project/settings.py b/core/settings.py similarity index 100% rename from cove_project/settings.py rename to core/settings.py diff --git a/cove_project/templates/terms.html b/core/templates/terms.html similarity index 100% rename from cove_project/templates/terms.html rename to core/templates/terms.html diff --git a/cove_project/urls.py b/core/urls.py similarity index 100% rename from cove_project/urls.py rename to core/urls.py diff --git a/cove_project/wsgi.py b/core/wsgi.py similarity index 72% rename from cove_project/wsgi.py rename to core/wsgi.py index bc339f7..a08c895 100644 --- a/cove_project/wsgi.py +++ b/core/wsgi.py @@ -1,5 +1,5 @@ """ -WSGI config for cove_project project. +WSGI config for core project. It exposes the WSGI callable as a module-level variable named ``application``. @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cove_project.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") application = get_wsgi_application() diff --git a/manage.py b/manage.py index 0c1fd3e..d68553b 100755 --- a/manage.py +++ b/manage.py @@ -3,7 +3,7 @@ import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cove_project.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") from django.core.management import execute_from_command_line diff --git a/pyproject.toml b/pyproject.toml index 13707c2..a368b7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,4 +28,4 @@ ignore-variadic-names = true ] [tool.pytest.ini_options] -DJANGO_SETTINGS_MODULE = 'cove_project.settings' +DJANGO_SETTINGS_MODULE = 'core.settings' From fec3c52f1a40a6ec987fdc0f93c1fdfc454b0d15 Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Mon, 30 Sep 2024 00:15:55 -0400 Subject: [PATCH 2/9] chore: Align with Django 4.2 --- core/asgi.py | 16 ++++++++++++++++ manage.py | 10 +++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 core/asgi.py diff --git a/core/asgi.py b/core/asgi.py new file mode 100644 index 0000000..66c1231 --- /dev/null +++ b/core/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for core project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") + +application = get_asgi_application() diff --git a/manage.py b/manage.py index d68553b..bd9928d 100755 --- a/manage.py +++ b/manage.py @@ -1,10 +1,18 @@ #!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" + import os import sys -if __name__ == "__main__": + +def main(): + """Run administrative tasks.""" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() From 9ff2d42e978c92e86b022bbe0d24f20a49e2bf37 Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Mon, 30 Sep 2024 00:17:15 -0400 Subject: [PATCH 3/9] chore: Upgrade to Python 3.11 --- .github/workflows/ci.yml | 2 +- .github/workflows/i18n.yml | 2 +- .github/workflows/lint.yml | 2 +- .pre-commit-config.yaml | 2 +- .python-version | 2 +- pyproject.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7132bdf..e31d612 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.11' cache: pip cache-dependency-path: '**/requirements*.txt' - run: pip install -r requirements.txt diff --git a/.github/workflows/i18n.yml b/.github/workflows/i18n.yml index b6b6040..a8d4f53 100644 --- a/.github/workflows/i18n.yml +++ b/.github/workflows/i18n.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.11' cache: pip cache-dependency-path: '**/requirements*.txt' - name: Install translate-toolkit diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2fc37d9..6a60c4c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,7 +14,7 @@ jobs: token: ${{ secrets.PAT || github.token }} - uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.11' cache: pip cache-dependency-path: '**/requirements*.txt' - id: changed-files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8d828bc..54e08b8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ ci: autoupdate_schedule: quarterly skip: [pip-compile] default_language_version: - python: python3.10 + python: python3.11 repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.3 diff --git a/.python-version b/.python-version index c8cfe39..2c07333 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.10 +3.11 diff --git a/pyproject.toml b/pyproject.toml index a368b7e..9a37b3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "0.0.0" [tool.ruff] line-length = 119 -target-version = "py310" +target-version = "py311" [tool.ruff.lint] select = ["ALL"] From ec8c00745eda654d3cf328113eb60b4499cb6153 Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Mon, 30 Sep 2024 00:18:55 -0400 Subject: [PATCH 4/9] feat: Add files for Docker. Rewrite settings.py to match cookiecutter and use Docker paths for media and db. --- .dockerignore | 26 +++++ .github/workflows/docker.yml | 38 ++++++ Dockerfile_django | 43 +++++++ Dockerfile_static | 17 +++ core/settings.py | 221 +++++++++++++++++++++++------------ default.conf | 56 +++++++++ 6 files changed, 329 insertions(+), 72 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker.yml create mode 100644 Dockerfile_django create mode 100644 Dockerfile_static create mode 100644 default.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b8f6dd2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,26 @@ +# Dotfiles +**/.* + +# Docker +**/Dockerfile* + +# Requirements +**/requirements.in +**/requirements_dev.in +**/requirements_dev.txt + +# Documentation +docs +LICENSE +README.md +README.rst + +# Configuration +pyproject.toml + +# Testing +**/tests +pytest.ini + +# Generated files +**/node_modules diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..508d90d --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,38 @@ +name: Deploy +on: + workflow_run: + workflows: ["CI"] + branches: [main] + types: + - completed +jobs: + docker: + if: ${{ github.event.workflow_run.conclusion == 'success' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # https://github.com/docker/login-action#github-container-registry + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # https://github.com/docker/setup-buildx-action#usage + - uses: docker/setup-buildx-action@v3 + # https://github.com/docker/build-push-action#usage + - uses: docker/build-push-action@v6 + with: + push: true + file: Dockerfile_django + tags: | + ghcr.io/${{ github.repository }}-django:latest + cache-from: type=gha + cache-to: type=gha,mode=max + - uses: docker/build-push-action@v6 + with: + push: true + file: Dockerfile_static + tags: | + ghcr.io/${{ github.repository }}-static:latest + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile_django b/Dockerfile_django new file mode 100644 index 0000000..96255db --- /dev/null +++ b/Dockerfile_django @@ -0,0 +1,43 @@ +FROM python:3.11 as build-stage + +COPY requirements.txt /tmp/requirements.txt +RUN pip install --no-cache-dir -r /tmp/requirements.txt + +WORKDIR /workdir + +COPY . . + +ENV DJANGO_ENV=production + +RUN python manage.py collectstatic --noinput -v2 + +FROM python:3.11 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + gettext \ + && rm -rf /var/lib/apt/lists/* + +RUN groupadd -r runner && useradd --no-log-init -r -g runner runner + +# Must match the settings.DATABASES default value. +RUN mkdir -p /data/db && chown -R runner:runner /data/db +# Must match the settings.MEDIA_ROOT default value. +RUN mkdir -p /data/media && chown -R runner:runner /data/media + +COPY requirements.txt /tmp/requirements.txt +RUN pip install --no-cache-dir -r /tmp/requirements.txt + +WORKDIR /workdir +USER runner:runner +COPY --chown=runner:runner . . + +# Django needs a copy of the staticfiles.json manifest file. +COPY --from=build-stage --chown=runner:runner /workdir/static/staticfiles.json /workdir/static/staticfiles.json + +ENV DJANGO_ENV=production +ENV WEB_CONCURRENCY=2 + +RUN python manage.py compilemessages + +EXPOSE 8000 +CMD ["gunicorn", "core.wsgi", "--bind", "0.0.0.0:8000", "--worker-tmp-dir", "/dev/shm", "--threads", "2", "--name", "cove"] diff --git a/Dockerfile_static b/Dockerfile_static new file mode 100644 index 0000000..a6360e8 --- /dev/null +++ b/Dockerfile_static @@ -0,0 +1,17 @@ +FROM python:{{ cookiecutter.python_version }} as build-stage + +COPY requirements.txt /tmp/requirements.txt +RUN pip install --no-cache-dir -r /tmp/requirements.txt + +WORKDIR /workdir +COPY . . + +ENV DJANGO_ENV=production + +RUN python manage.py collectstatic --noinput -v2 + +FROM nginxinc/nginx-unprivileged:latest as production-stage +USER root +COPY --from=build-stage --chown=nginx:root /workdir/static /usr/share/nginx/html/static +COPY --chown=nginx:root default.conf /etc/nginx/conf.d/default.conf +USER nginx diff --git a/core/settings.py b/core/settings.py index d367f9d..c5eb391 100644 --- a/core/settings.py +++ b/core/settings.py @@ -1,5 +1,5 @@ """ -Django settings for cove_project project. +Django settings for the project. Generated by 'django-admin startproject'. @@ -11,42 +11,33 @@ """ import os +from glob import glob from pathlib import Path -from cove import settings +import sentry_sdk +from sentry_sdk.integrations.django import DjangoIntegration +from sentry_sdk.integrations.logging import ignore_logger -# Build paths inside the project like this: BASE_DIR / "subdir". +production = os.getenv("DJANGO_ENV") == "production" +local_access = "LOCAL_ACCESS" in os.environ or "ALLOWED_HOSTS" not in os.environ + +# Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent -# We use the setting to choose whether to show the section about Sentry in the -# terms and conditions -SENTRY_DSN = os.getenv("SENTRY_DSN", "") -if SENTRY_DSN: - import sentry_sdk - from sentry_sdk.integrations.django import DjangoIntegration - from sentry_sdk.integrations.logging import ignore_logger +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ - ignore_logger("django.security.DisallowedHost") - sentry_sdk.init(dsn=SENTRY_DSN, integrations=[DjangoIntegration()]) +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.getenv("SECRET_KEY", "2n5k63x#a(xc@-!tpxisd)bd!3bimfr1prj-*t7tnl(*j+#$0k") -FATHOM = { - "domain": os.getenv("FATHOM_ANALYTICS_DOMAIN", "cdn.usefathom.com"), - "id": os.getenv("FATHOM_ANALYTICS_ID", ""), -} -VALIDATION_ERROR_LOCATIONS_LENGTH = settings.VALIDATION_ERROR_LOCATIONS_LENGTH -VALIDATION_ERROR_LOCATIONS_SAMPLE = settings.VALIDATION_ERROR_LOCATIONS_SAMPLE -DELETE_FILES_AFTER_DAYS = int(os.getenv("DELETE_FILES_AFTER_DAYS", "90")) +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = not production -# We can't take MEDIA_ROOT and MEDIA_URL from cove settings, -# ... otherwise the files appear under the BASE_DIR that is the Cove library install. -# That could get messy. We want them to appear in our directory. -MEDIA_ROOT = BASE_DIR / "media" -MEDIA_URL = "/infrastructure/media/" +ALLOWED_HOSTS = [".localhost", "127.0.0.1", "[::1]", "0.0.0.0"] # noqa: S104 # Docker +if "ALLOWED_HOSTS" in os.environ: + ALLOWED_HOSTS.extend(os.getenv("ALLOWED_HOSTS").split(",")) -SECRET_KEY = os.getenv("SECRET_KEY", "2n5k63x#a(xc@-!tpxisd)bd!3bimfr1prj-*t7tnl(*j+#$0k") -DEBUG = settings.DEBUG -ALLOWED_HOSTS = settings.ALLOWED_HOSTS # Application definition @@ -66,6 +57,7 @@ MIDDLEWARE = ( "django.middleware.cache.UpdateCacheMiddleware", + "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.locale.LocaleMiddleware", "django.middleware.common.CommonMiddleware", @@ -73,32 +65,45 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - "django.middleware.security.SecurityMiddleware", "cove.middleware.CoveConfigCurrentApp", "django.middleware.cache.FetchFromCacheMiddleware", ) +ROOT_URLCONF = "core.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "core" / "templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.template.context_processors.i18n", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "cove.context_processors.from_settings", + "core.context_processors.from_settings", + ], + }, + }, +] -ROOT_URLCONF = "cove_project.urls" +WSGI_APPLICATION = "core.wsgi.application" -TEMPLATES = settings.TEMPLATES -TEMPLATES[0]["DIRS"] = [BASE_DIR / "cove_project" / "templates"] -TEMPLATES[0]["OPTIONS"]["context_processors"].append( - "cove_project.context_processors.from_settings", -) -WSGI_APPLICATION = "cove_project.wsgi.application" +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases -# We can't take DATABASES from cove settings, -# ... otherwise the files appear under the BASE_DIR that is the Cove library install. -# That could get messy. We want them to appear in our directory. DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", - "NAME": os.getenv("DB_NAME", str(BASE_DIR / "db.sqlite3")), + "NAME": os.getenv("DATABASE_PATH", "/data/db/db.sqlite3" if production else str(BASE_DIR / "db.sqlite3")), } } + # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators @@ -121,36 +126,117 @@ # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ -LANGUAGE_CODE = settings.LANGUAGE_CODE -TIME_ZONE = settings.TIME_ZONE -USE_I18N = settings.USE_I18N -USE_TZ = settings.USE_TZ +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" -LANGUAGES = settings.LANGUAGES +USE_I18N = True + +USE_TZ = True -LOCALE_PATHS = (BASE_DIR / "cove_oc4ids" / "locale",) # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ -# We can't take STATIC_URL and STATIC_ROOT from cove settings, -# ... otherwise the files appear under the BASE_DIR that is the Cove library install. -# and that doesn't work with our standard Apache setup. -STATIC_URL = "infrastructure/static/" -STATIC_ROOT = BASE_DIR / "static" +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + -# Misc +# Project-specific Django configuration -LOGGING = settings.LOGGING -LOGGING["handlers"]["null"] = { - "class": "logging.NullHandler", +LOCALE_PATHS = glob(str(BASE_DIR / "**" / "locale")) + +STATIC_ROOT = BASE_DIR / "static" + +STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage", + }, } -LOGGING["loggers"]["django.security.DisallowedHost"] = { - "handlers": ["null"], - "propagate": False, + +# https://docs.djangoproject.com/en/4.2/topics/logging/#django-security +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "console": { + "format": "%(asctime)s %(levelname)s [%(name)s:%(lineno)s] %(message)s", + }, + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "formatter": "console", + }, + "null": { + "class": "logging.NullHandler", + }, + }, + "loggers": { + "": { + "handlers": ["console"], + "level": "INFO", + }, + "django.security.DisallowedHost": { + "handlers": ["null"], + "propagate": False, + }, + }, } -# OC4IDS Config +# https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ +if production and not local_access: + # Run: env DJANGO_ENV=production SECURE_HSTS_SECONDS=1 ./manage.py check --deploy + CSRF_COOKIE_SECURE = True + SESSION_COOKIE_SECURE = True + SECURE_SSL_REDIRECT = True + SECURE_REFERRER_POLICY = "same-origin" # default in Django >= 3.1 + + # https://docs.djangoproject.com/en/4.2/ref/middleware/#http-strict-transport-security + if "SECURE_HSTS_SECONDS" in os.environ: + SECURE_HSTS_SECONDS = int(os.getenv("SECURE_HSTS_SECONDS")) + SECURE_HSTS_INCLUDE_SUBDOMAINS = True + SECURE_HSTS_PRELOAD = True + +# https://docs.djangoproject.com/en/4.2/ref/settings/#secure-proxy-ssl-header +if "DJANGO_PROXY" in os.environ: + USE_X_FORWARDED_HOST = True + SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") + +LANGUAGES = ( + ("en", "English"), + ("es", "Spanish"), +) + +MEDIA_ROOT = os.getenv("MEDIA_ROOT", "/data/media/" if production else BASE_DIR / "media/") +MEDIA_URL = "media/" + +if production: + CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache", + "LOCATION": "127.0.0.1:11211", + } + } + + +# Dependency configuration + +if "SENTRY_DSN" in os.environ: + # https://docs.sentry.io/platforms/python/logging/#ignoring-a-logger + ignore_logger("django.security.DisallowedHost") + sentry_sdk.init( + dsn=os.getenv("SENTRY_DSN"), + integrations=[DjangoIntegration()], + traces_sample_rate=0, # The Sentry plan does not include Performance. + ) COVE_CONFIG = { # lib-cove-web options @@ -162,19 +248,10 @@ "support_email": "data@open-contracting.org", } -# Because of how the standard site proxies traffic, we want to use this -USE_X_FORWARDED_HOST = True -# This Cove is served from the same domain as another Django app. -# To make sure sessions and CSRF tokens don't clash, use different names. -# https://github.com/open-contracting/deploy/issues/188 -CSRF_COOKIE_NAME = "oc4idscsrftoken" -SESSION_COOKIE_NAME = "oc4idssessionid" +# Project configuration -if not DEBUG: - CACHES = { - "default": { - "BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache", - "LOCATION": "127.0.0.1:11211", - } - } +FATHOM = { + "domain": os.getenv("FATHOM_ANALYTICS_DOMAIN") or "cdn.usefathom.com", + "id": os.getenv("FATHOM_ANALYTICS_ID"), +} diff --git a/default.conf b/default.conf new file mode 100644 index 0000000..d4f4a75 --- /dev/null +++ b/default.conf @@ -0,0 +1,56 @@ +server { + listen 8080; + listen [::]:8080; + server_name localhost; + server_tokens off; + + #access_log /var/log/nginx/host.access.log main; + + location /media/ { + root /data; + } + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + + location /static/ { + expires max; + } + location = /static/staticfiles.json { + expires -1; + } + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} From b9a61827328383dde1ae83d94c402d5cf2ac4c7b Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:18:27 -0400 Subject: [PATCH 5/9] chore: Ignore ARG001 in pytest fixture --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 9a37b3e..2ab63ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ ignore-variadic-names = true "*/migrations/*" = ["E501"] "tests/*" = [ "D", "FBT003", "INP001", "PLR2004", "PT", "S", "TRY003", + "ARG001", # fixtures ] [tool.pytest.ini_options] From 9093623ed49a572d931a4537565cae318e01bc9d Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:25:36 -0400 Subject: [PATCH 6/9] chore: Remove link to favicon that doesn't exist --- core/settings.py | 2 +- cove_oc4ids/templates/cove_oc4ids/base.html | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/settings.py b/core/settings.py index c5eb391..8b2b525 100644 --- a/core/settings.py +++ b/core/settings.py @@ -235,7 +235,7 @@ sentry_sdk.init( dsn=os.getenv("SENTRY_DSN"), integrations=[DjangoIntegration()], - traces_sample_rate=0, # The Sentry plan does not include Performance. + traces_sample_rate=1.0, ) COVE_CONFIG = { diff --git a/cove_oc4ids/templates/cove_oc4ids/base.html b/cove_oc4ids/templates/cove_oc4ids/base.html index 493ba47..f832163 100644 --- a/cove_oc4ids/templates/cove_oc4ids/base.html +++ b/cove_oc4ids/templates/cove_oc4ids/base.html @@ -3,7 +3,6 @@ {% load static %} {% block after_head %} - {% include "cove_oc4ids/fathom.html" %} From 4061ceee0f512d6827db2b235ba222c91814f30b Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:37:01 -0400 Subject: [PATCH 7/9] ci: Run collectstatic to satisfy ManifestStaticFilesStorage --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e31d612..cca922e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ jobs: # Check requirements.txt contains production requirements. - run: ./manage.py --help - run: pip install -r requirements_dev.txt + - run: ./manage.py collectstatic --noinput -v2 - name: Run checks and tests env: PYTHONWARNINGS: error From 01a93bf056e4a550146630221bdb17bd45c74f96 Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:39:05 -0400 Subject: [PATCH 8/9] feat: Increase DATA_UPLOAD_MAX_MEMORY_SIZE to 5MB (2.5MB default) --- core/settings.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/settings.py b/core/settings.py index 8b2b525..cff3cc9 100644 --- a/core/settings.py +++ b/core/settings.py @@ -218,6 +218,9 @@ MEDIA_ROOT = os.getenv("MEDIA_ROOT", "/data/media/" if production else BASE_DIR / "media/") MEDIA_URL = "media/" +# https://docs.djangoproject.com/en/4.2/ref/settings/#data-upload-max-memory-size +DATA_UPLOAD_MAX_MEMORY_SIZE = 52428800 # 5 MB + if production: CACHES = { "default": { From b4f7a2d3dc09c8158189984e1d9d80fe97f9faae Mon Sep 17 00:00:00 2001 From: James McKinney <26463+jpmckinney@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:52:29 -0400 Subject: [PATCH 9/9] chore: Ignore /static --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 97162bf..4b3fbd7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ __pycache__ .coverage .ve /media +/static