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/ci.yml b/.github/workflows/ci.yml
index 713d465..cca922e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -8,13 +8,14 @@ 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
# 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
@@ -23,5 +24,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/.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/.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/.gitignore b/.gitignore
index 97162bf..4b3fbd7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ __pycache__
.coverage
.ve
/media
+/static
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/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/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/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/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/core/settings.py b/core/settings.py
new file mode 100644
index 0000000..cff3cc9
--- /dev/null
+++ b/core/settings.py
@@ -0,0 +1,260 @@
+"""
+Django settings for the project.
+
+Generated by 'django-admin startproject'.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/4.2/ref/settings/
+"""
+
+import os
+from glob import glob
+from pathlib import Path
+
+import sentry_sdk
+from sentry_sdk.integrations.django import DjangoIntegration
+from sentry_sdk.integrations.logging import ignore_logger
+
+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
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
+
+# 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")
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = not production
+
+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(","))
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+ "bootstrap3",
+ "cove",
+ "cove.input",
+ "cove_oc4ids",
+]
+
+
+MIDDLEWARE = (
+ "django.middleware.cache.UpdateCacheMiddleware",
+ "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",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+ "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",
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = "core.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.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
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/4.2/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/4.2/howto/static-files/
+
+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"
+
+
+# Project-specific Django configuration
+
+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",
+ },
+}
+
+# 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,
+ },
+ },
+}
+
+# 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/"
+
+# 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": {
+ "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=1.0,
+ )
+
+COVE_CONFIG = {
+ # lib-cove-web options
+ "app_name": "cove_oc4ids",
+ "app_base_template": "cove_oc4ids/base.html",
+ "app_verbose_name": "Open Contracting for Infrastructure Data Standards Review Tool",
+ "app_strapline": "Review your OC4IDS data.",
+ "input_methods": ["upload", "url", "text"],
+ "support_email": "data@open-contracting.org",
+}
+
+
+# Project configuration
+
+FATHOM = {
+ "domain": os.getenv("FATHOM_ANALYTICS_DOMAIN") or "cdn.usefathom.com",
+ "id": os.getenv("FATHOM_ANALYTICS_ID"),
+}
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/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" %}
diff --git a/cove_project/settings.py b/cove_project/settings.py
deleted file mode 100644
index d367f9d..0000000
--- a/cove_project/settings.py
+++ /dev/null
@@ -1,180 +0,0 @@
-"""
-Django settings for cove_project project.
-
-Generated by 'django-admin startproject'.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/4.2/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/4.2/ref/settings/
-"""
-
-import os
-from pathlib import Path
-
-from cove import settings
-
-# 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
-
- ignore_logger("django.security.DisallowedHost")
- sentry_sdk.init(dsn=SENTRY_DSN, integrations=[DjangoIntegration()])
-
-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"))
-
-# 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/"
-
-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
-
-INSTALLED_APPS = [
- "django.contrib.admin",
- "django.contrib.auth",
- "django.contrib.contenttypes",
- "django.contrib.sessions",
- "django.contrib.messages",
- "django.contrib.staticfiles",
- "bootstrap3",
- "cove",
- "cove.input",
- "cove_oc4ids",
-]
-
-
-MIDDLEWARE = (
- "django.middleware.cache.UpdateCacheMiddleware",
- "django.contrib.sessions.middleware.SessionMiddleware",
- "django.middleware.locale.LocaleMiddleware",
- "django.middleware.common.CommonMiddleware",
- "django.middleware.csrf.CsrfViewMiddleware",
- "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 = "cove_project.urls"
-
-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"
-
-# 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")),
- }
-}
-
-# Password validation
-# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
-
-AUTH_PASSWORD_VALIDATORS = [
- {
- "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
- },
- {
- "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
- },
- {
- "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
- },
- {
- "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
- },
-]
-
-
-# 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
-
-LANGUAGES = settings.LANGUAGES
-
-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"
-
-# Misc
-
-LOGGING = settings.LOGGING
-LOGGING["handlers"]["null"] = {
- "class": "logging.NullHandler",
-}
-LOGGING["loggers"]["django.security.DisallowedHost"] = {
- "handlers": ["null"],
- "propagate": False,
-}
-
-# OC4IDS Config
-
-COVE_CONFIG = {
- # lib-cove-web options
- "app_name": "cove_oc4ids",
- "app_base_template": "cove_oc4ids/base.html",
- "app_verbose_name": "Open Contracting for Infrastructure Data Standards Review Tool",
- "app_strapline": "Review your OC4IDS data.",
- "input_methods": ["upload", "url", "text"],
- "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"
-
-if not DEBUG:
- CACHES = {
- "default": {
- "BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
- "LOCATION": "127.0.0.1:11211",
- }
- }
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;
+ #}
+}
diff --git a/manage.py b/manage.py
index 0c1fd3e..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__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cove_project.settings")
+
+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()
diff --git a/pyproject.toml b/pyproject.toml
index 13707c2..2ab63ea 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"]
@@ -25,7 +25,8 @@ ignore-variadic-names = true
"*/migrations/*" = ["E501"]
"tests/*" = [
"D", "FBT003", "INP001", "PLR2004", "PT", "S", "TRY003",
+ "ARG001", # fixtures
]
[tool.pytest.ini_options]
-DJANGO_SETTINGS_MODULE = 'cove_project.settings'
+DJANGO_SETTINGS_MODULE = 'core.settings'