From b96c0b2635d2cdfb7601ae6f08062e704142156b Mon Sep 17 00:00:00 2001 From: JersyJ Date: Fri, 20 Sep 2024 02:42:48 +0200 Subject: [PATCH 01/12] Add services --- .env.example | 15 ++-- docker-compose-local.yml | 34 +++++++++ docker-compose.yml | 72 +++++++++++++++--- kelvin/asgi.py | 16 ++++ kelvin/settings.py | 24 +++--- nginx.conf | 47 ++++++++++++ pyproject.toml | 1 + sync_from_prod.sh | 2 +- uv.lock | 153 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 333 insertions(+), 31 deletions(-) create mode 100644 docker-compose-local.yml create mode 100644 kelvin/asgi.py create mode 100644 nginx.conf diff --git a/.env.example b/.env.example index 41ed7db6..cc466a35 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,10 @@ # PostgreSQL connection information -DB_HOST=127.0.0.1 -DB_DATABASE=kelvin -DB_USERNAME=kelvin -DB_PASSWORD=kelvin +DATABASE__HOSTNAME=localhost # Works only for local development +DATABASE__PORT=5432 +DATABASE__DB=kelvin +DATABASE__USERNAME=kelvin +DATABASE__PASSWORD=kelvin -# Path on the local disk where the data from a PostgreSQL instance running -# inside Docker will be stored -KELVIN_DB_PATH=./kelvin-data/db +# Redis connection information +REDIS__HOSTNAME=localhost # Works only for local development +REDIS__PORT=6379 diff --git a/docker-compose-local.yml b/docker-compose-local.yml new file mode 100644 index 00000000..019f4ee5 --- /dev/null +++ b/docker-compose-local.yml @@ -0,0 +1,34 @@ +# For local development, only database and redis is running +# +# docker compose -f docker-compose-local.yml up -d +# + +services: + db: + container_name: kelvin_local_db + image: postgres:14 + environment: + - POSTGRES_DB=${DATABASE__DB} + - POSTGRES_USER=${DATABASE__USERNAME} + - POSTGRES_PASSWORD=${DATABASE__PASSWORD} + env_file: + - .env + volumes: + - kelvin_local_db_data:/var/lib/postgresql/data + restart: unless-stopped + ports: + - "${DATABASE__PORT}:5432" + + redis: + container_name: kelvin_local_redis + image: redis:alpine + restart: unless-stopped + volumes: + - "kelvin_local_redis_data:/data" + ports: + - "${REDIS__PORT}:6379" + command: "redis-server --save 60 1 --loglevel warning" + +volumes: + kelvin_local_db_data: + kelvin_local_redis_data: diff --git a/docker-compose.yml b/docker-compose.yml index d5dc1fb9..32654348 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,66 @@ -version: "3.9" services: - db: - image: postgres:14 + app: + container_name: kelvin_app + depends_on: + - db + - redis + build: + context: . + dockerfile: Dockerfile + environment: + - DATABASE__HOSTNAME=db + - DATABASE__PORT=5432 + - DATABASE__DB=${DATABASE__DB} + - DATABASE__USERNAME=${DATABASE__USERNAME} + - DATABASE__PASSWORD=${DATABASE__PASSWORD} + - REDIS__HOST=redis + - REDIS__PORT=6379 + env_file: + - .env + restart: unless-stopped ports: - - "5432:5432" - volumes: - - ${KELVIN_DB_PATH?Absolute path to Kelvin database storage}:/var/lib/postgresql/data + - "${APP__PORT}:8000" + + db: container_name: kelvin_db + image: postgres:14 environment: - - POSTGRES_DB=${DB_DATABASE?Name of PostgreSQL database} - - POSTGRES_USER=${DB_USERNAME?PostgreSQL username} - - POSTGRES_PASSWORD=${DB_PASSWORD?PostgreSQL password} - redis: - image: redis + - POSTGRES_DB=${DATABASE__DB} + - POSTGRES_USER=${DATABASE__USERNAME} + - POSTGRES_PASSWORD=${DATABASE__PASSWORD} + env_file: + - .env + volumes: + - kelvin_db_data:/var/lib/postgresql/data + restart: unless-stopped ports: - - "6379:6379" + - "${DATABASE__PORT}:5432" + + redis: container_name: kelvin_redis + image: redis:alpine + restart: unless-stopped + env_file: + - .env + volumes: + - "kelvin_redis_data:/data" + ports: + - "${REDIS__PORT}:6379" + command: "redis-server --save 60 1 --loglevel warning" + + nginx: + image: nginx:alpine + container_name: kelvin_nginx + depends_on: + - app + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + - ./certs:/etc/nginx/certs:ro + - ./logs:/var/log/nginx + +volumes: + kelvin_db_data: + kelvin_redis_data: diff --git a/kelvin/asgi.py b/kelvin/asgi.py new file mode 100644 index 00000000..59496e52 --- /dev/null +++ b/kelvin/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for kelvin 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', 'kelvin.settings') + +application = get_asgi_application() diff --git a/kelvin/settings.py b/kelvin/settings.py index b5dc992e..f8caa3b6 100644 --- a/kelvin/settings.py +++ b/kelvin/settings.py @@ -31,9 +31,9 @@ SECRET_KEY = "***REMOVED***" # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = bool(os.environ.get("DEBUG", default=0)) -ALLOWED_HOSTS = ["127.0.0.1", "localhost", "web"] +ALLOWED_HOSTS = ["127.0.0.1", "localhost", "app", "kelvin.cs.vsb.cz"] # Application definition @@ -105,10 +105,12 @@ DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", - "HOST": os.getenv("DB_HOST", "127.0.0.1"), - "USER": os.getenv("DB_USERNAME"), - "PASSWORD": os.getenv("DB_PASSWORD"), - "NAME": os.getenv("DB_DATABASE"), + "HOST": os.getenv("DATABASE__HOSTNAME", "127.0.0.1"), + "PORT": os.getenv("DATABASE__PORT", 5432), + "NAME": os.getenv("DATABASE__DB"), + "USER": os.getenv("DATABASE__USERNAME"), + "PASSWORD": os.getenv("DATABASE__PASSWORD"), + } } @@ -175,14 +177,14 @@ CAS_CREATE_USER = False CAS_FORCE_CHANGE_USERNAME_CASE = "upper" -redis_host = os.getenv("REDIS_HOST", "127.0.0.1") -redis_port = os.getenv("REDIS_EXPOSE_PORT", 6379) -redis_connection = f"redis://{redis_host}:{redis_port}/0" +REDIS_HOST = os.getenv("REDIS__HOST", "127.0.0.1") +REDIS_PORT = os.getenv("REDIS__PORT", 6379) +REDIS_CONNECTION = f"redis://{REDIS_HOST}:{REDIS_PORT}/0" CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": redis_connection, + "LOCATION": REDIS_CONNECTION, "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", }, @@ -204,7 +206,7 @@ } # For django-tasks-scheduler -SCHEDULER_QUEUES = {"default": {"HOST": redis_host, "PORT": redis_port}} +SCHEDULER_QUEUES = {"default": {"HOST": REDIS_HOST, "PORT": REDIS_PORT}} LOGGING = { "version": 1, diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 00000000..21aa1921 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,47 @@ +events { + worker_connections 1024; +} + +http { + upstream django { + server kelvin_app:8000; # Uvicorn running Django app + } + + server { + listen 443 ssl; + server_name yourdomain.com; + + ssl_certificate /etc/nginx/certs/fullchain.pem; + ssl_certificate_key /etc/nginx/certs/privkey.pem; + + location / { + proxy_pass http://django; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Serve static files + location /static/ { + alias /path/to/collected/static/; # Path to the folder where Django's collectstatic command puts static files + } + + # Serve media files + location /media/ { + alias /path/to/media/; # Path to the media folder + } + + error_page 404 /404.html; + location = /404.html { + root /path/to/error/pages; + } + } + + # Redirect all HTTP requests to HTTPS + server { + listen 80; + server_name yourdomain.com; + return 301 https://$host$request_uri; + } +} diff --git a/pyproject.toml b/pyproject.toml index 81f30b87..0e57607a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ dependencies = [ "typing-extensions==4.11.0", "Unidecode==1.3.6", "uWSGI==2.0.24", + "uvicorn[standard]>=0.30.6", ] [tool.uv] diff --git a/sync_from_prod.sh b/sync_from_prod.sh index 194b096c..1f689c52 100755 --- a/sync_from_prod.sh +++ b/sync_from_prod.sh @@ -1,7 +1,7 @@ #!/bin/bash . .env set -ex -ssh kelvin@kelvin.cs.vsb.cz pg_dump --clean kelvin | docker exec -i kelvin_db psql -U "$DB_USERNAME" -d "$DB_DATABASE" +ssh kelvin@kelvin.cs.vsb.cz pg_dump --clean kelvin | docker exec -i kelvin_db psql -U "$DATABASE__USERNAME" -d "$DATABASE__DB" rsync -avzP kelvin@kelvin.cs.vsb.cz:kelvin/tasks . rsync -avzP kelvin@kelvin.cs.vsb.cz:kelvin/submits/2023-W submits/ rsync -avzP kelvin@kelvin.cs.vsb.cz:kelvin/survey/surveys survey/ diff --git a/uv.lock b/uv.lock index 07fa060c..68c5cef9 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,19 @@ version = 1 requires-python = ">=3.12" +[[package]] +name = "anyio" +version = "4.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a0/44/66874c5256e9fbc30103b31927fd9341c8da6ccafd4721b2b3e81e6ef176/anyio-4.5.0.tar.gz", hash = "sha256:c5a275fe5ca0afd788001f58fca1e69e29ce706d746e317d660e21f70c530ef9", size = 169376 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/68/f9e9bf6324c46e6b8396610aef90ad423ec3e18c9079547ceafea3dce0ec/anyio-4.5.0-py3-none-any.whl", hash = "sha256:fdeb095b7cc5a5563175eedd926ec4ae55413bb4be5770c424af0ba46ccb4a78", size = 89250 }, +] + [[package]] name = "asgiref" version = "3.7.1" @@ -318,6 +331,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/a4/50a6ae300a71fdfb94bd172365884d52f602454adb52a7823665fb9df94c/django_webpush-0.3.4-py3-none-any.whl", hash = "sha256:a2613784e822e2dde27086fb20b6d1a2b76e4d5dc8271607aecd45c98a3b7954", size = 28350 }, ] +[[package]] +name = "h11" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, +] + [[package]] name = "http-ece" version = "1.2.0" @@ -327,6 +349,21 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/12/b5/bcbc98aa8d0c5f08e99136c801d05910858abc42ac9df17d3f58e730b4ab/http_ece-1.2.0.tar.gz", hash = "sha256:b5920f8efb8e1b5fb025713e3b36fda54336262010634b26dc1f98f85d1eb3de", size = 8771 } +[[package]] +name = "httptools" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/67/1d/d77686502fced061b3ead1c35a2d70f6b281b5f723c4eff7a2277c04e4a2/httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a", size = 191228 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/13/b62e086b650752adf9094b7e62dab97f4cb7701005664544494b7956a51e/httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0", size = 146354 }, + { url = "https://files.pythonhosted.org/packages/f8/5d/9ad32b79b6c24524087e78aa3f0a2dfcf58c11c90e090e4593b35def8a86/httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2", size = 75785 }, + { url = "https://files.pythonhosted.org/packages/d0/a4/b503851c40f20bcbd453db24ed35d961f62abdae0dccc8f672cd5d350d87/httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90", size = 345396 }, + { url = "https://files.pythonhosted.org/packages/a2/9a/aa406864f3108e06f7320425a528ff8267124dead1fd72a3e9da2067f893/httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503", size = 344741 }, + { url = "https://files.pythonhosted.org/packages/cf/3a/3fd8dfb987c4247651baf2ac6f28e8e9f889d484ca1a41a9ad0f04dfe300/httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84", size = 345096 }, + { url = "https://files.pythonhosted.org/packages/80/01/379f6466d8e2edb861c1f44ccac255ed1f8a0d4c5c666a1ceb34caad7555/httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb", size = 343535 }, + { url = "https://files.pythonhosted.org/packages/d3/97/60860e9ee87a7d4712b98f7e1411730520053b9d69e9e42b0b9751809c17/httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949", size = 55660 }, +] + [[package]] name = "idna" version = "3.6" @@ -410,6 +447,7 @@ dependencies = [ { name = "six" }, { name = "typing-extensions" }, { name = "unidecode" }, + { name = "uvicorn", extra = ["standard"] }, { name = "uwsgi" }, ] @@ -452,6 +490,7 @@ requires-dist = [ { name = "six", specifier = "==1.16.0" }, { name = "typing-extensions", specifier = "==4.11.0" }, { name = "unidecode", specifier = "==1.3.6" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.30.6" }, { name = "uwsgi", specifier = "==2.0.24" }, ] @@ -863,6 +902,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, ] +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, +] + [[package]] name = "soupsieve" version = "2.5" @@ -957,12 +1005,117 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", size = 121444 }, ] +[[package]] +name = "uvicorn" +version = "0.30.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/01/5e637e7aa9dd031be5376b9fb749ec20b86f5a5b6a49b87fabd374d5fa9f/uvicorn-0.30.6.tar.gz", hash = "sha256:4b15decdda1e72be08209e860a1e10e92439ad5b97cf44cc945fcbee66fc5788", size = 42825 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/8e/cdc7d6263db313030e4c257dd5ba3909ebc4e4fb53ad62d5f09b1a2f5458/uvicorn-0.30.6-py3-none-any.whl", hash = "sha256:65fd46fe3fda5bdc1b03b94eb634923ff18cd35b2f084813ea79d1f103f711b5", size = 62835 }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/f1/dc9577455e011ad43d9379e836ee73f40b4f99c02946849a44f7ae64835e/uvloop-0.20.0.tar.gz", hash = "sha256:4603ca714a754fc8d9b197e325db25b2ea045385e8a3ad05d3463de725fdf469", size = 2329938 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/64/31cbd379d6e260ac8de3f672f904e924f09715c3f192b09f26cc8e9f574c/uvloop-0.20.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4b75f2950ddb6feed85336412b9a0c310a2edbcf4cf931aa5cfe29034829676d", size = 1324302 }, + { url = "https://files.pythonhosted.org/packages/1e/6b/9207e7177ff30f78299401f2e1163ea41130d4fd29bcdc6d12572c06b728/uvloop-0.20.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:77fbc69c287596880ecec2d4c7a62346bef08b6209749bf6ce8c22bbaca0239e", size = 738105 }, + { url = "https://files.pythonhosted.org/packages/c1/ba/b64b10f577519d875992dc07e2365899a1a4c0d28327059ce1e1bdfb6854/uvloop-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6462c95f48e2d8d4c993a2950cd3d31ab061864d1c226bbf0ee2f1a8f36674b9", size = 4090658 }, + { url = "https://files.pythonhosted.org/packages/0a/f8/5ceea6876154d926604f10c1dd896adf9bce6d55a55911364337b8a5ed8d/uvloop-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649c33034979273fa71aa25d0fe120ad1777c551d8c4cd2c0c9851d88fcb13ab", size = 4173357 }, + { url = "https://files.pythonhosted.org/packages/18/b2/117ab6bfb18274753fbc319607bf06e216bd7eea8be81d5bac22c912d6a7/uvloop-0.20.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a609780e942d43a275a617c0839d85f95c334bad29c4c0918252085113285b5", size = 4029868 }, + { url = "https://files.pythonhosted.org/packages/6f/52/deb4be09060637ef4752adaa0b75bf770c20c823e8108705792f99cd4a6f/uvloop-0.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aea15c78e0d9ad6555ed201344ae36db5c63d428818b4b2a42842b3870127c00", size = 4115980 }, +] + [[package]] name = "uwsgi" version = "2.0.24" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1b/ed/136698c76722268569eac4e48ab90f3ced8b8035e414a8290cb935c40c16/uwsgi-2.0.24.tar.gz", hash = "sha256:77b6dd5cd633f4ae87ee393f7701f617736815499407376e78f3d16467523afe", size = 810559 } +[[package]] +name = "watchfiles" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137 }, + { url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733 }, + { url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322 }, + { url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409 }, + { url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142 }, + { url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414 }, + { url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962 }, + { url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705 }, + { url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851 }, + { url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868 }, + { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 }, + { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 }, + { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 }, + { url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 }, + { url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 }, + { url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 }, + { url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 }, + { url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 }, + { url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 }, + { url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 }, + { url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 }, + { url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 }, + { url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 }, + { url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 }, + { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 }, +] + +[[package]] +name = "websockets" +version = "13.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/1c/78687e0267b09412409ac134f10fd14d14ac6475da892a8b09a02d0f6ae2/websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e", size = 149769 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/51/23ed2d239f1c3087c1431d41cfd159865df0bc35bb0c89973e3b6a0fff9b/websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a", size = 150953 }, + { url = "https://files.pythonhosted.org/packages/57/8d/814a7ef62b916b0f39108ad2e4d9b4cb0f8c640f8c30202fb63041598ada/websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956", size = 148610 }, + { url = "https://files.pythonhosted.org/packages/ad/8b/a378d21124011737e0e490a8a6ef778914b03e50c8d938de2f2170a20dbd/websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af", size = 148849 }, + { url = "https://files.pythonhosted.org/packages/46/d2/814a61226af313c1bc289cfe3a10f87bf426b6f2d9df0f927c47afab7612/websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf", size = 158772 }, + { url = "https://files.pythonhosted.org/packages/a1/7e/5987299eb7e131216c9027b05a65f149cbc2bde7c582e694d9eed6ec3d40/websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c", size = 157724 }, + { url = "https://files.pythonhosted.org/packages/94/6e/eaf95894042ba8a05a125fe8bcf9ee3572fef6edbcbf49478f4991c027cc/websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4", size = 158152 }, + { url = "https://files.pythonhosted.org/packages/ce/ba/a1315d569cc2dadaafda74a9cea16ab5d68142525937f1994442d969b306/websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab", size = 158442 }, + { url = "https://files.pythonhosted.org/packages/90/9b/59866695cfd05e785c90932fef3dae4682eb4e06e7076b7c53478f25faad/websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d", size = 157823 }, + { url = "https://files.pythonhosted.org/packages/9b/47/20af68a313b6453d2d094ccc497b7232e8475175d234e3e5bef5088521e5/websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237", size = 157818 }, + { url = "https://files.pythonhosted.org/packages/f8/bb/60aaedc80e388e978617dda1ff38788780c6b0f6e462b85368cb934131a5/websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185", size = 151785 }, + { url = "https://files.pythonhosted.org/packages/16/2e/e47692f569e1be2e66c1dbc5e85ea4d2cc93b80027fbafa28ae8b0dee52c/websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99", size = 152214 }, + { url = "https://files.pythonhosted.org/packages/46/37/d8ef4b68684d1fa368a5c64be466db07fc58b68163bc2496db2d4cc208ff/websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa", size = 150962 }, + { url = "https://files.pythonhosted.org/packages/95/49/78aeb3af08ec9887a9065e85cef9d7e199d6c6261fcd39eec087f3a62328/websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231", size = 148621 }, + { url = "https://files.pythonhosted.org/packages/31/0d/dc9b7cec8deaee452092a631ccda894bd7098859f71dd7639b4b5b9c615c/websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9", size = 148853 }, + { url = "https://files.pythonhosted.org/packages/16/bf/734cbd815d7bc94cffe35c934f4e08b619bf3b47df1c6c7af21c1d35bcfe/websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75", size = 158741 }, + { url = "https://files.pythonhosted.org/packages/af/9b/756f89b12fee8931785531a314e6f087b21774a7f8c60878e597c684f91b/websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553", size = 157690 }, + { url = "https://files.pythonhosted.org/packages/d3/37/31f97132d2262e666b797e250879ca833eab55115f88043b3952a2840eb8/websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920", size = 158132 }, + { url = "https://files.pythonhosted.org/packages/41/ce/59c8d44e148c002fec506a9527504fb4281676e2e75c2ee5a58180f1b99a/websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329", size = 158490 }, + { url = "https://files.pythonhosted.org/packages/1a/74/5b31ce0f318b902c0d70c031f8e1228ba1a4d95a46b2a24a2a5ac17f9cf0/websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7", size = 157879 }, + { url = "https://files.pythonhosted.org/packages/0d/a7/6eac4f04177644bbc98deb98d11770cc7fbc216f6f67ab187c150540fd52/websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2", size = 157873 }, + { url = "https://files.pythonhosted.org/packages/72/f6/b8b30a3b134dfdb4ccd1694befa48fddd43783957c988a1dab175732af33/websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb", size = 151782 }, + { url = "https://files.pythonhosted.org/packages/3e/88/d94ccc006c69583168aa9dd73b3f1885c8931f2c676f4bdd8cbfae91c7b6/websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b", size = 152212 }, + { url = "https://files.pythonhosted.org/packages/fd/bd/d34c4b7918453506d2149208b175368738148ffc4ba256d7fd8708956732/websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817", size = 145262 }, +] + [[package]] name = "wrapt" version = "1.16.0" From 1b19a9d5ced12e58088cee63596ef1baa02c3558 Mon Sep 17 00:00:00 2001 From: JersyJ Date: Fri, 20 Sep 2024 02:59:47 +0200 Subject: [PATCH 02/12] Add nginx --- docker-compose.yml | 16 ++++++++++++++-- nginx.conf | 18 ++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 32654348..52df1853 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,7 @@ services: depends_on: - db - redis + - nginx build: context: . dockerfile: Dockerfile @@ -17,9 +18,16 @@ services: - REDIS__PORT=6379 env_file: - .env + volumes: + - kelvin_app_static:/app/static + - kelvin_app_media:/app/media + - ./local_settings.py:/app/local_settings.py:ro restart: unless-stopped - ports: - - "${APP__PORT}:8000" + expose: + - "8000" + command: > + sh -c "python3 manage.py collectstatic --noinput && + python3 manage.py runserver 0.0.0.0:8000" db: container_name: kelvin_db @@ -60,7 +68,11 @@ services: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./certs:/etc/nginx/certs:ro - ./logs:/var/log/nginx + - kelvin_app_static:/app/static + - kelvin_app_media:/app/media volumes: kelvin_db_data: kelvin_redis_data: + kelvin_app_static: + kelvin_app_media: diff --git a/nginx.conf b/nginx.conf index 21aa1921..52c2cf4f 100644 --- a/nginx.conf +++ b/nginx.conf @@ -3,6 +3,12 @@ events { } http { + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + upstream django { server kelvin_app:8000; # Uvicorn running Django app } @@ -20,22 +26,22 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + proxy_buffering off; } # Serve static files location /static/ { - alias /path/to/collected/static/; # Path to the folder where Django's collectstatic command puts static files + alias /app/static/; # Path to the folder where Django's collectstatic command puts static files } # Serve media files location /media/ { - alias /path/to/media/; # Path to the media folder + alias /app/media/; # Path to the media folder } - error_page 404 /404.html; - location = /404.html { - root /path/to/error/pages; - } } # Redirect all HTTP requests to HTTPS From 007fe8b4131fb199114617ad93217054a072fa16 Mon Sep 17 00:00:00 2001 From: JersyJ Date: Fri, 20 Sep 2024 19:03:51 +0200 Subject: [PATCH 03/12] Dockerfile for app done --- .dockerignore | 1 - .env.example | 8 +++++ .gitignore | 4 +++ Dockerfile | 78 ++++++++++++++++++++++++++++++++++++---------- docker-compose.yml | 25 +++++---------- kelvin/settings.py | 5 ++- kelvin/urls.py | 3 +- nginx.conf | 7 +---- 8 files changed, 89 insertions(+), 42 deletions(-) diff --git a/.dockerignore b/.dockerignore index 5b2b585a..8b8a99bc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,3 @@ tasks/ submits/ submit_results/ -frontend/ diff --git a/.env.example b/.env.example index cc466a35..ddd8873b 100644 --- a/.env.example +++ b/.env.example @@ -8,3 +8,11 @@ DATABASE__PASSWORD=kelvin # Redis connection information REDIS__HOSTNAME=localhost # Works only for local development REDIS__PORT=6379 + +DATABASE__DATA_PATH=./kelvin_data/data +REDIS__DATA_PATH=./kelvin_data/redis +NGINX__LOGS_PATH=./kelvin_data/logs/nginx + +NGINX__CERTS_PATH=./certs +NGINX__CONFIG_PATH=./nginx.conf +KELVIN__LOCAL_SETTINGS_PATH=./local_settings.py diff --git a/.gitignore b/.gitignore index 7ace7037..4ae38fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,7 @@ web/static/dolos survey/surveys/*.yaml exams/ + +static/ + +kelvin_data/ diff --git a/Dockerfile b/Dockerfile index 409c4cd1..b014126d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,68 @@ -FROM python:3.12 +FROM python:3.12-bookworm AS build-backend-stage -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONUNBUFFERED=1 +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get install -y libsasl2-dev libgraphviz-dev graphviz -RUN apt-get update && apt-get install -y libsasl2-dev libgraphviz-dev graphviz +RUN pip install uv==0.4.12 -COPY requirements.txt /kelvin/requirements.txt -RUN pip install -r /kelvin/requirements.txt +WORKDIR /app -RUN apt-get update \ - && apt-get install -y ca-certificates curl gnupg lsb-release \ - && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list \ - && apt-get update \ - && apt-get install -y docker-ce docker-ce-cli containerd.io +COPY pyproject.toml uv.lock ./ + +RUN uv sync + +FROM node:22.9.0-bookworm-slim AS build-frontend-stage + +WORKDIR /frontend + +COPY frontend . + +RUN mkdir -p /web/static + +RUN ls -la + +RUN npm run build + +FROM python:3.12-bookworm AS runtime + +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y libsasl2-dev libgraphviz-dev graphviz + +WORKDIR /app + +COPY --from=build-backend-stage /app . + +ENV PATH="/app/.venv/bin:$PATH" + +COPY kelvin ./kelvin + +COPY web ./web + +COPY --from=build-frontend-stage /web/static/frontend.css /web/static/frontend.js /web/static/dolos ./web/static/ + +COPY templates ./templates + +COPY evaluator ./evaluator + +COPY survey ./survey + +COPY common ./common + +COPY api ./api + +COPY manage.py . + +# Create new user to run app process as unprivilaged user +RUN groupadd --gid 1001 uvicorn && \ + useradd --uid 1001 --gid 1001 --shell /bin/false --system uvicorn + +RUN chown -R uvicorn:uvicorn /app + +USER uvicorn -WORKDIR /kelvin +RUN python manage.py collectstatic --no-input -#RUN addgroup --gid 1000 user -#RUN adduser --disabled-password --gecos '' --uid $HOST_USER_ID --gid 1000 user -#USER user +CMD ["uvicorn", "kelvin.asgi:application", "--host", "0.0.0.0", "--port", "8000"] +EXPOSE 8000 diff --git a/docker-compose.yml b/docker-compose.yml index 52df1853..2308052a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,15 +19,11 @@ services: env_file: - .env volumes: - - kelvin_app_static:/app/static - - kelvin_app_media:/app/media - - ./local_settings.py:/app/local_settings.py:ro + - ${DATABASE__DATA_PATH}:/app/static + - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/local_settings.py:ro restart: unless-stopped expose: - "8000" - command: > - sh -c "python3 manage.py collectstatic --noinput && - python3 manage.py runserver 0.0.0.0:8000" db: container_name: kelvin_db @@ -39,7 +35,7 @@ services: env_file: - .env volumes: - - kelvin_db_data:/var/lib/postgresql/data + - ${DATABASE__DATA_PATH}:/var/lib/postgresql/data restart: unless-stopped ports: - "${DATABASE__PORT}:5432" @@ -51,7 +47,7 @@ services: env_file: - .env volumes: - - "kelvin_redis_data:/data" + - ${REDIS__DATA_PATH}:/data ports: - "${REDIS__PORT}:6379" command: "redis-server --save 60 1 --loglevel warning" @@ -65,14 +61,9 @@ services: - "80:80" - "443:443" volumes: - - ./nginx.conf:/etc/nginx/nginx.conf:ro - - ./certs:/etc/nginx/certs:ro - - ./logs:/var/log/nginx - - kelvin_app_static:/app/static - - kelvin_app_media:/app/media - + - ${NGINX__CONFIG_PATH}:/etc/nginx/nginx.conf:ro + - ${NGINX__CERTS_PATH}:/etc/nginx/certs:ro + - ${NGINX__LOGS_PATH}:/var/log/nginx + - kelvin_app_static:/var/www/kelvin/static volumes: - kelvin_db_data: - kelvin_redis_data: kelvin_app_static: - kelvin_app_media: diff --git a/kelvin/settings.py b/kelvin/settings.py index f8caa3b6..c8e935c1 100644 --- a/kelvin/settings.py +++ b/kelvin/settings.py @@ -31,7 +31,7 @@ SECRET_KEY = "***REMOVED***" # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = bool(os.environ.get("DEBUG", default=0)) +DEBUG = True ALLOWED_HOSTS = ["127.0.0.1", "localhost", "app", "kelvin.cs.vsb.cz"] @@ -151,6 +151,9 @@ STATIC_URL = "/static/" STATIC_ROOT = os.path.join(BASE_DIR, "static") +MEDIA_URL = "/media/" +MEDIA_ROOT = os.path.join(BASE_DIR, "media") + STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", diff --git a/kelvin/urls.py b/kelvin/urls.py index 3d9edeae..faee3013 100644 --- a/kelvin/urls.py +++ b/kelvin/urls.py @@ -17,6 +17,7 @@ from django.contrib import admin from django.urls import path, include from django.conf import settings +from django.conf.urls.static import static # import notifications.urls @@ -36,7 +37,7 @@ path("webpush/", include("webpush.urls")), # For django-tasks-scheduler path("scheduler/", include("scheduler.urls")), -] +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) if settings.DEBUG: from django.contrib.auth import login as login_fn diff --git a/nginx.conf b/nginx.conf index 52c2cf4f..67a8ef22 100644 --- a/nginx.conf +++ b/nginx.conf @@ -34,12 +34,7 @@ http { # Serve static files location /static/ { - alias /app/static/; # Path to the folder where Django's collectstatic command puts static files - } - - # Serve media files - location /media/ { - alias /app/media/; # Path to the media folder + alias /var/www/kelvin/static/; } } From 4dbde9f2a43c0f6f1d170ced655dcfb8f852ccaf Mon Sep 17 00:00:00 2001 From: JersyJ Date: Fri, 20 Sep 2024 19:48:44 +0200 Subject: [PATCH 04/12] First part done --- Dockerfile | 2 -- docker-compose.yml | 5 ++--- kelvin/settings.py | 2 +- nginx.conf | 5 ++++- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index b014126d..971e7205 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,6 @@ COPY frontend . RUN mkdir -p /web/static -RUN ls -la - RUN npm run build FROM python:3.12-bookworm AS runtime diff --git a/docker-compose.yml b/docker-compose.yml index 2308052a..26784045 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,6 @@ services: depends_on: - db - redis - - nginx build: context: . dockerfile: Dockerfile @@ -19,7 +18,7 @@ services: env_file: - .env volumes: - - ${DATABASE__DATA_PATH}:/app/static + - kelvin_app_static:/app/static - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/local_settings.py:ro restart: unless-stopped expose: @@ -64,6 +63,6 @@ services: - ${NGINX__CONFIG_PATH}:/etc/nginx/nginx.conf:ro - ${NGINX__CERTS_PATH}:/etc/nginx/certs:ro - ${NGINX__LOGS_PATH}:/var/log/nginx - - kelvin_app_static:/var/www/kelvin/static + - kelvin_app_static:/app/static volumes: kelvin_app_static: diff --git a/kelvin/settings.py b/kelvin/settings.py index c8e935c1..370a8303 100644 --- a/kelvin/settings.py +++ b/kelvin/settings.py @@ -31,7 +31,7 @@ SECRET_KEY = "***REMOVED***" # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = DEBUG = bool(os.environ.get("DEBUG", default=False)) ALLOWED_HOSTS = ["127.0.0.1", "localhost", "app", "kelvin.cs.vsb.cz"] diff --git a/nginx.conf b/nginx.conf index 67a8ef22..aa88ebd7 100644 --- a/nginx.conf +++ b/nginx.conf @@ -9,6 +9,7 @@ http { '' close; } + upstream django { server kelvin_app:8000; # Uvicorn running Django app } @@ -34,7 +35,9 @@ http { # Serve static files location /static/ { - alias /var/www/kelvin/static/; + autoindex on; + alias /app/static/; + include /etc/nginx/mime.types; } } From 484f08e489e9d86986d7c9b17ae30e36d3f1a586 Mon Sep 17 00:00:00 2001 From: JersyJ Date: Fri, 20 Sep 2024 20:07:38 +0200 Subject: [PATCH 05/12] Fix CSRF --- kelvin/settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kelvin/settings.py b/kelvin/settings.py index 370a8303..75360d47 100644 --- a/kelvin/settings.py +++ b/kelvin/settings.py @@ -31,10 +31,12 @@ SECRET_KEY = "***REMOVED***" # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = DEBUG = bool(os.environ.get("DEBUG", default=False)) +DEBUG = bool(os.environ.get("DEBUG", default=0)) ALLOWED_HOSTS = ["127.0.0.1", "localhost", "app", "kelvin.cs.vsb.cz"] +CSRF_TRUSTED_ORIGINS = ["https://127.0.0.1", "https://localhost", "https://app", "https://kelvin.cs.vsb.cz"] + # Application definition INSTALLED_APPS = [ From 36a09cbbd8e7a34f425c1118da124a4380e4c39b Mon Sep 17 00:00:00 2001 From: JersyJ Date: Sat, 21 Sep 2024 20:41:24 +0200 Subject: [PATCH 06/12] Refactor Dockerfile --- .dockerignore | 1 + .env.example | 7 ++++ Dockerfile | 59 +++++++++++++++++++-------------- docker-compose-local.yml | 34 ------------------- docker-compose.prod.yml | 70 ++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 60 ++++++++-------------------------- 6 files changed, 125 insertions(+), 106 deletions(-) delete mode 100644 docker-compose-local.yml create mode 100644 docker-compose.prod.yml diff --git a/.dockerignore b/.dockerignore index 8b8a99bc..f43c12ab 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,4 @@ tasks/ submits/ submit_results/ +.venv/ \ No newline at end of file diff --git a/.env.example b/.env.example index ddd8873b..1e63bc54 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,6 @@ +# Django SETTINGS +DEBUG=1 + # PostgreSQL connection information DATABASE__HOSTNAME=localhost # Works only for local development DATABASE__PORT=5432 @@ -9,10 +12,14 @@ DATABASE__PASSWORD=kelvin REDIS__HOSTNAME=localhost # Works only for local development REDIS__PORT=6379 +# Data storage paths DATABASE__DATA_PATH=./kelvin_data/data REDIS__DATA_PATH=./kelvin_data/redis + +# Logs paths NGINX__LOGS_PATH=./kelvin_data/logs/nginx +# Configuration paths NGINX__CERTS_PATH=./certs NGINX__CONFIG_PATH=./nginx.conf KELVIN__LOCAL_SETTINGS_PATH=./local_settings.py diff --git a/Dockerfile b/Dockerfile index 971e7205..886d4917 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,19 @@ -FROM python:3.12-bookworm AS build-backend-stage +FROM ghcr.io/astral-sh/uv:python3.12-bookworm AS build-backend-stage -RUN export DEBIAN_FRONTEND=noninteractive \ - && apt-get update \ - && apt-get install -y libsasl2-dev libgraphviz-dev graphviz - -RUN pip install uv==0.4.12 +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y \ + -o APT::Install-Recommends=false \ + -o APT::Install-Suggests=false \ + libsasl2-dev \ + libgraphviz-dev \ + graphviz WORKDIR /app COPY pyproject.toml uv.lock ./ -RUN uv sync +RUN --mount=type=cache,target=/root/.cache uv sync --frozen --no-dev --no-install-project --compile-bytecode FROM node:22.9.0-bookworm-slim AS build-frontend-stage @@ -25,42 +28,48 @@ RUN npm run build FROM python:3.12-bookworm AS runtime RUN export DEBIAN_FRONTEND=noninteractive && \ - apt-get update && \ - apt-get install -y libsasl2-dev libgraphviz-dev graphviz + apt-get update && \ + apt-get install -y \ + -o APT::Install-Recommends=false \ + -o APT::Install-Suggests=false \ + graphviz && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* WORKDIR /app -COPY --from=build-backend-stage /app . +# Create new user to run app process as unprivilaged user +RUN groupadd --gid 1001 uvicorn && \ + useradd --uid 1001 --gid 1001 --shell /bin/false --system uvicorn -ENV PATH="/app/.venv/bin:$PATH" +RUN chown -R uvicorn:uvicorn /app -COPY kelvin ./kelvin +COPY --from=build-backend-stage --chown=uvicorn:uvicorn /app . -COPY web ./web +ENV PATH="/app/.venv/bin:$PATH" -COPY --from=build-frontend-stage /web/static/frontend.css /web/static/frontend.js /web/static/dolos ./web/static/ +COPY --chown=uvicorn:uvicorn kelvin ./kelvin -COPY templates ./templates +COPY --chown=uvicorn:uvicorn web ./web -COPY evaluator ./evaluator +COPY --from=build-frontend-stage --chown=uvicorn:uvicorn /web/static/frontend.css /web/static/frontend.js /web/static/dolos ./web/static/ -COPY survey ./survey +COPY --chown=uvicorn:uvicorn templates ./templates -COPY common ./common +COPY --chown=uvicorn:uvicorn evaluator ./evaluator -COPY api ./api +COPY --chown=uvicorn:uvicorn survey ./survey -COPY manage.py . +COPY --chown=uvicorn:uvicorn common ./common -# Create new user to run app process as unprivilaged user -RUN groupadd --gid 1001 uvicorn && \ - useradd --uid 1001 --gid 1001 --shell /bin/false --system uvicorn +COPY --chown=uvicorn:uvicorn api ./api -RUN chown -R uvicorn:uvicorn /app +COPY --chown=uvicorn:uvicorn manage.py . USER uvicorn RUN python manage.py collectstatic --no-input -CMD ["uvicorn", "kelvin.asgi:application", "--host", "0.0.0.0", "--port", "8000"] EXPOSE 8000 + +CMD ["uvicorn", "kelvin.asgi:application", "--host", "0.0.0.0", "--port", "8000"] diff --git a/docker-compose-local.yml b/docker-compose-local.yml deleted file mode 100644 index 019f4ee5..00000000 --- a/docker-compose-local.yml +++ /dev/null @@ -1,34 +0,0 @@ -# For local development, only database and redis is running -# -# docker compose -f docker-compose-local.yml up -d -# - -services: - db: - container_name: kelvin_local_db - image: postgres:14 - environment: - - POSTGRES_DB=${DATABASE__DB} - - POSTGRES_USER=${DATABASE__USERNAME} - - POSTGRES_PASSWORD=${DATABASE__PASSWORD} - env_file: - - .env - volumes: - - kelvin_local_db_data:/var/lib/postgresql/data - restart: unless-stopped - ports: - - "${DATABASE__PORT}:5432" - - redis: - container_name: kelvin_local_redis - image: redis:alpine - restart: unless-stopped - volumes: - - "kelvin_local_redis_data:/data" - ports: - - "${REDIS__PORT}:6379" - command: "redis-server --save 60 1 --loglevel warning" - -volumes: - kelvin_local_db_data: - kelvin_local_redis_data: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 00000000..7633e7af --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,70 @@ +services: + app: + container_name: kelvin_app + depends_on: + - db + - redis + build: + context: . + dockerfile: Dockerfile + target: runtime + environment: + - DATABASE__HOSTNAME=db + - DATABASE__PORT=5432 + - DATABASE__DB=${DATABASE__DB} + - DATABASE__USERNAME=${DATABASE__USERNAME} + - DATABASE__PASSWORD=${DATABASE__PASSWORD} + - REDIS__HOST=redis + - REDIS__PORT=6379 + env_file: + - .env + volumes: + - kelvin_app_static:/app/static + - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/local_settings.py:ro + restart: unless-stopped + expose: + - "8000" + + db: + container_name: kelvin_db + image: postgres:14 + environment: + - POSTGRES_DB=${DATABASE__DB} + - POSTGRES_USER=${DATABASE__USERNAME} + - POSTGRES_PASSWORD=${DATABASE__PASSWORD} + env_file: + - .env + volumes: + - ${DATABASE__DATA_PATH}:/var/lib/postgresql/data + restart: unless-stopped + ports: + - "${DATABASE__PORT}:5432" + + redis: + container_name: kelvin_redis + image: redis:alpine + restart: unless-stopped + env_file: + - .env + volumes: + - ${REDIS__DATA_PATH}:/data + ports: + - "${REDIS__PORT}:6379" + command: "redis-server --save 60 1 --loglevel warning" + + nginx: + image: nginx:alpine + container_name: kelvin_nginx + depends_on: + - app + ports: + - "80:80" + - "443:443" + volumes: + - ${NGINX__CONFIG_PATH}:/etc/nginx/nginx.conf:ro + - ${NGINX__CERTS_PATH}:/etc/nginx/certs:ro + - ${NGINX__LOGS_PATH}:/var/log/nginx + - kelvin_app_static:/app/static + +volumes: + kelvin_app_static: diff --git a/docker-compose.yml b/docker-compose.yml index 26784045..8faebfc0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,32 +1,12 @@ -services: - app: - container_name: kelvin_app - depends_on: - - db - - redis - build: - context: . - dockerfile: Dockerfile - environment: - - DATABASE__HOSTNAME=db - - DATABASE__PORT=5432 - - DATABASE__DB=${DATABASE__DB} - - DATABASE__USERNAME=${DATABASE__USERNAME} - - DATABASE__PASSWORD=${DATABASE__PASSWORD} - - REDIS__HOST=redis - - REDIS__PORT=6379 - env_file: - - .env - volumes: - - kelvin_app_static:/app/static - - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/local_settings.py:ro - restart: unless-stopped - expose: - - "8000" +# For local development, only database and redis is running +# +# docker compose up -d +# +services: db: - container_name: kelvin_db - image: postgres:14 + container_name: kelvin_local_db + image: postgres:14 environment: - POSTGRES_DB=${DATABASE__DB} - POSTGRES_USER=${DATABASE__USERNAME} @@ -34,35 +14,21 @@ services: env_file: - .env volumes: - - ${DATABASE__DATA_PATH}:/var/lib/postgresql/data + - kelvin_local_db_data:/var/lib/postgresql/data restart: unless-stopped ports: - "${DATABASE__PORT}:5432" - + redis: - container_name: kelvin_redis + container_name: kelvin_local_redis image: redis:alpine restart: unless-stopped - env_file: - - .env volumes: - - ${REDIS__DATA_PATH}:/data + - "kelvin_local_redis_data:/data" ports: - "${REDIS__PORT}:6379" command: "redis-server --save 60 1 --loglevel warning" - nginx: - image: nginx:alpine - container_name: kelvin_nginx - depends_on: - - app - ports: - - "80:80" - - "443:443" - volumes: - - ${NGINX__CONFIG_PATH}:/etc/nginx/nginx.conf:ro - - ${NGINX__CERTS_PATH}:/etc/nginx/certs:ro - - ${NGINX__LOGS_PATH}:/var/log/nginx - - kelvin_app_static:/app/static volumes: - kelvin_app_static: + kelvin_local_db_data: + kelvin_local_redis_data: From 295b70d9a2fe1ca5a42ab515a094ad9d33f319d5 Mon Sep 17 00:00:00 2001 From: JersyJ Date: Sat, 21 Sep 2024 21:38:05 +0200 Subject: [PATCH 07/12] Add pre-commit --- .dockerignore | 2 +- .env.example | 2 +- .pre-commit-config.yaml | 28 +++++++++++++ Dockerfile | 2 +- docker-compose.prod.yml | 2 +- docker-compose.yml | 2 +- kelvin/asgi.py | 2 +- kelvin/settings.py | 8 +++- nginx.conf | 2 +- pyproject.toml | 3 +- uv.lock | 90 ++++++++++++++++++++++++++++++++++++++++- 11 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.dockerignore b/.dockerignore index f43c12ab..e21449cb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,4 @@ tasks/ submits/ submit_results/ -.venv/ \ No newline at end of file +.venv/ diff --git a/.env.example b/.env.example index 1e63bc54..ba9379e5 100644 --- a/.env.example +++ b/.env.example @@ -10,7 +10,7 @@ DATABASE__PASSWORD=kelvin # Redis connection information REDIS__HOSTNAME=localhost # Works only for local development -REDIS__PORT=6379 +REDIS__PORT=6379 # Data storage paths DATABASE__DATA_PATH=./kelvin_data/data diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..a8bb7af7 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,28 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-yaml + args: [--allow-multiple-documents] + - id: check-json + - id: check-toml + - id: check-shebang-scripts-are-executable + - id: end-of-file-fixer + name: Makes sure files end in a newline and only a newline. + entry: end-of-file-fixer + types: [text] + - id: trailing-whitespace + name: Trims trailing whitespace. + entry: trailing-whitespace-fixer + types: [text] + - id: mixed-line-ending + args: [ --fix=lf ] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.7 + hooks: + - id: ruff-format + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.7 + hooks: + - id: ruff + args: [ --fix ] diff --git a/Dockerfile b/Dockerfile index 886d4917..a63b7835 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,7 +33,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ -o APT::Install-Recommends=false \ -o APT::Install-Suggests=false \ graphviz && \ - apt-get clean && \ + apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* WORKDIR /app diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 7633e7af..7efd1cb7 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -39,7 +39,7 @@ services: restart: unless-stopped ports: - "${DATABASE__PORT}:5432" - + redis: container_name: kelvin_redis image: redis:alpine diff --git a/docker-compose.yml b/docker-compose.yml index 8faebfc0..b7ede3d7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: db: container_name: kelvin_local_db - image: postgres:14 + image: postgres:14 environment: - POSTGRES_DB=${DATABASE__DB} - POSTGRES_USER=${DATABASE__USERNAME} diff --git a/kelvin/asgi.py b/kelvin/asgi.py index 59496e52..d274e2c6 100644 --- a/kelvin/asgi.py +++ b/kelvin/asgi.py @@ -11,6 +11,6 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'kelvin.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kelvin.settings") application = get_asgi_application() diff --git a/kelvin/settings.py b/kelvin/settings.py index 75360d47..ae40e360 100644 --- a/kelvin/settings.py +++ b/kelvin/settings.py @@ -35,7 +35,12 @@ ALLOWED_HOSTS = ["127.0.0.1", "localhost", "app", "kelvin.cs.vsb.cz"] -CSRF_TRUSTED_ORIGINS = ["https://127.0.0.1", "https://localhost", "https://app", "https://kelvin.cs.vsb.cz"] +CSRF_TRUSTED_ORIGINS = [ + "https://127.0.0.1", + "https://localhost", + "https://app", + "https://kelvin.cs.vsb.cz", +] # Application definition @@ -112,7 +117,6 @@ "NAME": os.getenv("DATABASE__DB"), "USER": os.getenv("DATABASE__USERNAME"), "PASSWORD": os.getenv("DATABASE__PASSWORD"), - } } diff --git a/nginx.conf b/nginx.conf index aa88ebd7..26d2f744 100644 --- a/nginx.conf +++ b/nginx.conf @@ -8,7 +8,7 @@ http { default upgrade; '' close; } - + upstream django { server kelvin_app:8000; # Uvicorn running Django app diff --git a/pyproject.toml b/pyproject.toml index 0e57607a..b5fc1df7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,5 +44,6 @@ dependencies = [ [tool.uv] dev-dependencies = [ - "ruff==0.6.3" + "pre-commit>=3.8.0", + "ruff==0.6.3", ] diff --git a/uv.lock b/uv.lock index 68c5cef9..1623618c 100644 --- a/uv.lock +++ b/uv.lock @@ -99,6 +99,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/63/e285470a4880a4f36edabe4810057bd4b562c6ddcc165eacf9c3c7210b40/cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", size = 181956 }, ] +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, +] + [[package]] name = "charset-normalizer" version = "3.3.2" @@ -221,6 +230,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/8d/778b7d51b981a96554f29136cd59ca7880bf58094338085bcf2a979a0e6a/Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c", size = 9561 }, ] +[[package]] +name = "distlib" +version = "0.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/91/e2df406fb4efacdf46871c25cde65d3c6ee5e173b7e5a4547a47bae91920/distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64", size = 609931 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/41/9307e4f5f9976bc8b7fea0b66367734e8faf3ec84bc0d412d8cfabbb66cd/distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", size = 468850 }, +] + [[package]] name = "django" version = "4.2.16" @@ -331,6 +349,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/a4/50a6ae300a71fdfb94bd172365884d52f602454adb52a7823665fb9df94c/django_webpush-0.3.4-py3-none-any.whl", hash = "sha256:a2613784e822e2dde27086fb20b6d1a2b76e4d5dc8271607aecd45c98a3b7954", size = 28350 }, ] +[[package]] +name = "filelock" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, +] + [[package]] name = "h11" version = "0.14.0" @@ -364,6 +391,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d3/97/60860e9ee87a7d4712b98f7e1411730520053b9d69e9e42b0b9751809c17/httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949", size = 55660 }, ] +[[package]] +name = "identify" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/bb/25024dbcc93516c492b75919e76f389bac754a3e4248682fba32b250c880/identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98", size = 99097 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/0c/4ef72754c050979fdcc06c744715ae70ea37e734816bb6514f79df77a42f/identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0", size = 98972 }, +] + [[package]] name = "idna" version = "3.6" @@ -453,6 +489,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "pre-commit" }, { name = "ruff" }, ] @@ -495,7 +532,10 @@ requires-dist = [ ] [package.metadata.requires-dev] -dev = [{ name = "ruff", specifier = "==0.6.3" }] +dev = [ + { name = "pre-commit", specifier = ">=3.8.0" }, + { name = "ruff", specifier = "==0.6.3" }, +] [[package]] name = "lxml" @@ -563,6 +603,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9b/cd/dc52755d30ba41c60243235460961fc28022e5b6731f16c268667625baea/networkx-2.5-py3-none-any.whl", hash = "sha256:8c5812e9f798d37c50570d15c4a69d5710a18d77bafc903ee9c5fba7454c616c", size = 1615413 }, ] +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, +] + [[package]] name = "numpy" version = "1.26.4" @@ -637,6 +686,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/61/6cff8a8dbbac3d7fb7adb435b60737a7d0b0849f53e3af38f2c94d988da6/pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", size = 2229322 }, ] +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, +] + [[package]] name = "plum-dispatch" version = "2.2.2" @@ -649,6 +707,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/45/07/95c6be6710207f4a2c83023f59889a86c58282c8367aa49a907e9e6deb57/plum_dispatch-2.2.2-py3-none-any.whl", hash = "sha256:d7ee415bd166ffa90eaa4b24d7c9dc7ca6f8875750586001e7c9baff706223bd", size = 30137 }, ] +[[package]] +name = "pre-commit" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/10/97ee2fa54dff1e9da9badbc5e35d0bbaef0776271ea5907eccf64140f72f/pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", size = 177815 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/92/caae8c86e94681b42c246f0bca35c059a2f0529e5b92619f6aba4cf7e7b6/pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f", size = 204643 }, +] + [[package]] name = "psycopg" version = "3.2.1" @@ -1049,6 +1123,20 @@ version = "2.0.24" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1b/ed/136698c76722268569eac4e48ab90f3ced8b8035e414a8290cb935c40c16/uwsgi-2.0.24.tar.gz", hash = "sha256:77b6dd5cd633f4ae87ee393f7701f617736815499407376e78f3d16467523afe", size = 810559 } +[[package]] +name = "virtualenv" +version = "20.26.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/4c/66ce54c8736ff164e85117ca36b02a1e14c042a6963f85eeda82664fda4e/virtualenv-20.26.5.tar.gz", hash = "sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4", size = 9371932 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/1d/e1a44fdd6d30829ba21fc58b5d98a67e7aae8f4165f11d091e53aec12560/virtualenv-20.26.5-py3-none-any.whl", hash = "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6", size = 5999288 }, +] + [[package]] name = "watchfiles" version = "0.24.0" From 8c710eb677e6a35d88845d2daacea6e0472e7603 Mon Sep 17 00:00:00 2001 From: JersyJ Date: Sun, 22 Sep 2024 01:05:27 +0200 Subject: [PATCH 08/12] Address comments --- .env.example | 7 ++--- Dockerfile | 20 ++++-------- docker-compose.prod.yml | 70 ----------------------------------------- docker-compose.yml | 66 +++++++++++++++++++++++++++++--------- docs/setup.md | 6 ++++ kelvin/settings.py | 5 +-- kelvin/urls.py | 3 +- 7 files changed, 68 insertions(+), 109 deletions(-) delete mode 100644 docker-compose.prod.yml diff --git a/.env.example b/.env.example index ba9379e5..f09c970a 100644 --- a/.env.example +++ b/.env.example @@ -1,15 +1,12 @@ -# Django SETTINGS -DEBUG=1 - # PostgreSQL connection information -DATABASE__HOSTNAME=localhost # Works only for local development +DATABASE__HOSTNAME=127.0.0.1 DATABASE__PORT=5432 DATABASE__DB=kelvin DATABASE__USERNAME=kelvin DATABASE__PASSWORD=kelvin # Redis connection information -REDIS__HOSTNAME=localhost # Works only for local development +REDIS__HOSTNAME=127.0.0.1 REDIS__PORT=6379 # Data storage paths diff --git a/Dockerfile b/Dockerfile index a63b7835..80274f4a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/astral-sh/uv:python3.12-bookworm AS build-backend-stage +FROM ghcr.io/astral-sh/uv:python3.12-bookworm AS build-backend RUN export DEBIAN_FRONTEND=noninteractive && \ apt-get update && \ @@ -13,9 +13,9 @@ WORKDIR /app COPY pyproject.toml uv.lock ./ -RUN --mount=type=cache,target=/root/.cache uv sync --frozen --no-dev --no-install-project --compile-bytecode +RUN uv sync --frozen --no-dev --no-install-project --compile-bytecode -FROM node:22.9.0-bookworm-slim AS build-frontend-stage +FROM node:22.9.0-bookworm-slim AS build-frontend WORKDIR /frontend @@ -44,26 +44,18 @@ RUN groupadd --gid 1001 uvicorn && \ RUN chown -R uvicorn:uvicorn /app -COPY --from=build-backend-stage --chown=uvicorn:uvicorn /app . - +COPY --from=build-backend --chown=uvicorn:uvicorn /app . ENV PATH="/app/.venv/bin:$PATH" -COPY --chown=uvicorn:uvicorn kelvin ./kelvin - COPY --chown=uvicorn:uvicorn web ./web +COPY --from=build-frontend --chown=uvicorn:uvicorn /web/static/frontend.[js|css]|dolos ./web/static/ -COPY --from=build-frontend-stage --chown=uvicorn:uvicorn /web/static/frontend.css /web/static/frontend.js /web/static/dolos ./web/static/ - +COPY --chown=uvicorn:uvicorn kelvin ./kelvin COPY --chown=uvicorn:uvicorn templates ./templates - COPY --chown=uvicorn:uvicorn evaluator ./evaluator - COPY --chown=uvicorn:uvicorn survey ./survey - COPY --chown=uvicorn:uvicorn common ./common - COPY --chown=uvicorn:uvicorn api ./api - COPY --chown=uvicorn:uvicorn manage.py . USER uvicorn diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml deleted file mode 100644 index 7efd1cb7..00000000 --- a/docker-compose.prod.yml +++ /dev/null @@ -1,70 +0,0 @@ -services: - app: - container_name: kelvin_app - depends_on: - - db - - redis - build: - context: . - dockerfile: Dockerfile - target: runtime - environment: - - DATABASE__HOSTNAME=db - - DATABASE__PORT=5432 - - DATABASE__DB=${DATABASE__DB} - - DATABASE__USERNAME=${DATABASE__USERNAME} - - DATABASE__PASSWORD=${DATABASE__PASSWORD} - - REDIS__HOST=redis - - REDIS__PORT=6379 - env_file: - - .env - volumes: - - kelvin_app_static:/app/static - - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/local_settings.py:ro - restart: unless-stopped - expose: - - "8000" - - db: - container_name: kelvin_db - image: postgres:14 - environment: - - POSTGRES_DB=${DATABASE__DB} - - POSTGRES_USER=${DATABASE__USERNAME} - - POSTGRES_PASSWORD=${DATABASE__PASSWORD} - env_file: - - .env - volumes: - - ${DATABASE__DATA_PATH}:/var/lib/postgresql/data - restart: unless-stopped - ports: - - "${DATABASE__PORT}:5432" - - redis: - container_name: kelvin_redis - image: redis:alpine - restart: unless-stopped - env_file: - - .env - volumes: - - ${REDIS__DATA_PATH}:/data - ports: - - "${REDIS__PORT}:6379" - command: "redis-server --save 60 1 --loglevel warning" - - nginx: - image: nginx:alpine - container_name: kelvin_nginx - depends_on: - - app - ports: - - "80:80" - - "443:443" - volumes: - - ${NGINX__CONFIG_PATH}:/etc/nginx/nginx.conf:ro - - ${NGINX__CERTS_PATH}:/etc/nginx/certs:ro - - ${NGINX__LOGS_PATH}:/var/log/nginx - - kelvin_app_static:/app/static - -volumes: - kelvin_app_static: diff --git a/docker-compose.yml b/docker-compose.yml index b7ede3d7..67d96e85 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,33 @@ -# For local development, only database and redis is running -# -# docker compose up -d -# - services: + app: + container_name: kelvin_app + depends_on: + - db + - redis + profiles: [prod] + build: + context: . + dockerfile: Dockerfile + target: runtime + environment: + - DATABASE__HOSTNAME=db + - DATABASE__PORT=5432 + - DATABASE__DB=${DATABASE__DB} + - DATABASE__USERNAME=${DATABASE__USERNAME} + - DATABASE__PASSWORD=${DATABASE__PASSWORD} + - REDIS__HOST=redis + - REDIS__PORT=6379 + env_file: + - .env + volumes: + - kelvin_app_static:/app/static + - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/local_settings.py:ro + restart: unless-stopped + expose: + - "8000" + db: - container_name: kelvin_local_db + container_name: kelvin_db image: postgres:14 environment: - POSTGRES_DB=${DATABASE__DB} @@ -14,21 +36,37 @@ services: env_file: - .env volumes: - - kelvin_local_db_data:/var/lib/postgresql/data + - ${DATABASE__DATA_PATH}:/var/lib/postgresql/data restart: unless-stopped ports: - - "${DATABASE__PORT}:5432" + - "${DATABASE__HOSTNAME}:${DATABASE__PORT}:5432" redis: - container_name: kelvin_local_redis - image: redis:alpine + container_name: kelvin_redis + image: redis:latest restart: unless-stopped + env_file: + - .env volumes: - - "kelvin_local_redis_data:/data" + - ${REDIS__DATA_PATH}:/data ports: - - "${REDIS__PORT}:6379" + - "${REDIS__HOSTNAME}:${REDIS__PORT}:6379" command: "redis-server --save 60 1 --loglevel warning" + nginx: + image: nginx:stable + container_name: kelvin_nginx + depends_on: + - app + profiles: [prod] + ports: + - "80:80" + - "443:443" + volumes: + - ${NGINX__CONFIG_PATH}:/etc/nginx/nginx.conf:ro + - ${NGINX__CERTS_PATH}:/etc/nginx/certs:ro + - ${NGINX__LOGS_PATH}:/var/log/nginx + - kelvin_app_static:/app/static + volumes: - kelvin_local_db_data: - kelvin_local_redis_data: + kelvin_app_static: diff --git a/docs/setup.md b/docs/setup.md index 30a854b1..6475583d 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -22,6 +22,12 @@ Do not forget to activate the virtual environment if you want to work with Pytho $ source .venv/bin/activate ``` +## Git pre-commit hooks +To ensure that the code is formatted correctly and linted, you can install pre-commit hooks: +```bash +$ pre-commit install +``` + ## Building the frontend For building the frontend, you'll need `npm`: ```bash diff --git a/kelvin/settings.py b/kelvin/settings.py index ae40e360..e313f88c 100644 --- a/kelvin/settings.py +++ b/kelvin/settings.py @@ -31,7 +31,7 @@ SECRET_KEY = "***REMOVED***" # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = bool(os.environ.get("DEBUG", default=0)) +DEBUG = True ALLOWED_HOSTS = ["127.0.0.1", "localhost", "app", "kelvin.cs.vsb.cz"] @@ -157,9 +157,6 @@ STATIC_URL = "/static/" STATIC_ROOT = os.path.join(BASE_DIR, "static") -MEDIA_URL = "/media/" -MEDIA_ROOT = os.path.join(BASE_DIR, "media") - STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", diff --git a/kelvin/urls.py b/kelvin/urls.py index faee3013..3d9edeae 100644 --- a/kelvin/urls.py +++ b/kelvin/urls.py @@ -17,7 +17,6 @@ from django.contrib import admin from django.urls import path, include from django.conf import settings -from django.conf.urls.static import static # import notifications.urls @@ -37,7 +36,7 @@ path("webpush/", include("webpush.urls")), # For django-tasks-scheduler path("scheduler/", include("scheduler.urls")), -] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +] if settings.DEBUG: from django.contrib.auth import login as login_fn From 913106261d7988f6d32ec3d2496441d9ab61dc33 Mon Sep 17 00:00:00 2001 From: JersyJ Date: Sun, 22 Sep 2024 20:59:12 +0200 Subject: [PATCH 09/12] Change to WSGI and move to deploy --- .dockerignore | 1 + .env.example | 11 +++- Dockerfile | 38 ++++++----- deploy/entrypoint.sh | 5 ++ deploy/nginx.conf | 39 +++++++++++ deploy/uwsgi.ini | 20 ++++++ docker-compose.yml | 17 +++-- nginx.conf | 51 --------------- pyproject.toml | 18 ++++- ruff.toml | 16 ----- uv.lock | 153 ------------------------------------------- 11 files changed, 123 insertions(+), 246 deletions(-) create mode 100755 deploy/entrypoint.sh create mode 100644 deploy/nginx.conf create mode 100644 deploy/uwsgi.ini delete mode 100644 nginx.conf delete mode 100644 ruff.toml diff --git a/.dockerignore b/.dockerignore index e21449cb..8d02ebe4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,4 @@ tasks/ submits/ submit_results/ .venv/ +node_modules/ diff --git a/.env.example b/.env.example index f09c970a..6af7f255 100644 --- a/.env.example +++ b/.env.example @@ -13,10 +13,15 @@ REDIS__PORT=6379 DATABASE__DATA_PATH=./kelvin_data/data REDIS__DATA_PATH=./kelvin_data/redis + + +# Production only + # Logs paths NGINX__LOGS_PATH=./kelvin_data/logs/nginx # Configuration paths -NGINX__CERTS_PATH=./certs -NGINX__CONFIG_PATH=./nginx.conf -KELVIN__LOCAL_SETTINGS_PATH=./local_settings.py +NGINX__CERTS_PATH=./deploy/certs +NGINX__CONFIG_PATH=./deploy/nginx.conf +UWSGI__CONFIG_PATH=./deploy/uwsgi.ini +KELVIN__LOCAL_SETTINGS_PATH=./deploy/local_settings.py diff --git a/Dockerfile b/Dockerfile index 80274f4a..7bb1fdbd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,8 @@ COPY frontend . RUN mkdir -p /web/static +RUN npm ci + RUN npm run build FROM python:3.12-bookworm AS runtime @@ -39,29 +41,33 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ WORKDIR /app # Create new user to run app process as unprivilaged user -RUN groupadd --gid 1001 uvicorn && \ - useradd --uid 1001 --gid 1001 --shell /bin/false --system uvicorn +RUN groupadd --gid 102 webserver && \ + useradd --uid 101 --gid 102 --shell /bin/false --system webserver -RUN chown -R uvicorn:uvicorn /app +RUN chown -R webserver:webserver /app -COPY --from=build-backend --chown=uvicorn:uvicorn /app . +COPY --from=build-backend --chown=webserver:webserver /app . ENV PATH="/app/.venv/bin:$PATH" -COPY --chown=uvicorn:uvicorn web ./web -COPY --from=build-frontend --chown=uvicorn:uvicorn /web/static/frontend.[js|css]|dolos ./web/static/ +COPY --chown=webserver:webserver web ./web +COPY --from=build-frontend --chown=uvicorn:uvicorn /web/static/frontend.* ./web/static/ +COPY --from=build-frontend --chown=uvicorn:uvicorn /web/static/dolos ./web/static/dolos +COPY --chown=webserver:webserver kelvin ./kelvin +COPY --chown=webserver:webserver templates ./templates +COPY --chown=webserver:webserver evaluator ./evaluator +COPY --chown=webserver:webserver survey ./survey +COPY --chown=webserver:webserver common ./common +COPY --chown=webserver:webserver api ./api +COPY --chown=webserver:webserver manage.py . -COPY --chown=uvicorn:uvicorn kelvin ./kelvin -COPY --chown=uvicorn:uvicorn templates ./templates -COPY --chown=uvicorn:uvicorn evaluator ./evaluator -COPY --chown=uvicorn:uvicorn survey ./survey -COPY --chown=uvicorn:uvicorn common ./common -COPY --chown=uvicorn:uvicorn api ./api -COPY --chown=uvicorn:uvicorn manage.py . +RUN mkdir -p /socket && chown webserver:webserver /socket -USER uvicorn +USER webserver -RUN python manage.py collectstatic --no-input +RUN python manage.py collectstatic --no-input --clear EXPOSE 8000 -CMD ["uvicorn", "kelvin.asgi:application", "--host", "0.0.0.0", "--port", "8000"] +COPY --chown=webserver:webserver deploy/entrypoint.sh ./ +ENTRYPOINT [ "/app/entrypoint.sh" ] +STOPSIGNAL SIGINT diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh new file mode 100755 index 00000000..00963edf --- /dev/null +++ b/deploy/entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +python manage.py migrate + +exec uwsgi --ini uwsgi.ini diff --git a/deploy/nginx.conf b/deploy/nginx.conf new file mode 100644 index 00000000..0988b281 --- /dev/null +++ b/deploy/nginx.conf @@ -0,0 +1,39 @@ +events { + worker_connections 1024; +} + +http { + + upstream django { + server unix:///socket/kelvin.sock; + } + + server { + listen 443 ssl; + server_name kelvin.cs.vsb.cz; + charset utf-8; + + ssl_certificate /etc/nginx/certs/fullchain.pem; + ssl_certificate_key /etc/nginx/certs/privkey.pem; + + location / { + uwsgi_pass django; + include uwsgi_params; + } + + # Serve static files + location /static/ { + autoindex on; + alias /app/static/; + include /etc/nginx/mime.types; + } + + } + + # Redirect all HTTP requests to HTTPS + server { + listen 80; + server_name kelvin.cs.vsb.cz; + return 301 https://$host$request_uri; + } +} diff --git a/deploy/uwsgi.ini b/deploy/uwsgi.ini new file mode 100644 index 00000000..56ba3ed8 --- /dev/null +++ b/deploy/uwsgi.ini @@ -0,0 +1,20 @@ +[uwsgi] + +# Django-related settings +# the base directory (full path) +chdir = /app +# Django's wsgi file +module = kelvin.wsgi + +# process-related settings +# master +master = true +# maximum number of worker processes +processes = 5 +# the socket (use the full path to be safe +socket = /socket/kelvin.sock +chmod-socket = 664 +# clear environment on exit +vacuum = true + +max-requests = 5000 diff --git a/docker-compose.yml b/docker-compose.yml index 67d96e85..16af0089 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,7 @@ services: context: . dockerfile: Dockerfile target: runtime + restart: unless-stopped environment: - DATABASE__HOSTNAME=db - DATABASE__PORT=5432 @@ -20,15 +21,17 @@ services: env_file: - .env volumes: - - kelvin_app_static:/app/static - - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/local_settings.py:ro - restart: unless-stopped + - app_static:/app/static + - app_socket:/socket + - ${KELVIN__LOCAL_SETTINGS_PATH}:/app/kelvin/local_settings.py:ro + - ${UWSGI__CONFIG_PATH}:/app/uwsgi.ini:ro expose: - "8000" db: container_name: kelvin_db image: postgres:14 + restart: unless-stopped environment: - POSTGRES_DB=${DATABASE__DB} - POSTGRES_USER=${DATABASE__USERNAME} @@ -37,7 +40,6 @@ services: - .env volumes: - ${DATABASE__DATA_PATH}:/var/lib/postgresql/data - restart: unless-stopped ports: - "${DATABASE__HOSTNAME}:${DATABASE__PORT}:5432" @@ -58,6 +60,7 @@ services: container_name: kelvin_nginx depends_on: - app + restart: unless-stopped profiles: [prod] ports: - "80:80" @@ -66,7 +69,9 @@ services: - ${NGINX__CONFIG_PATH}:/etc/nginx/nginx.conf:ro - ${NGINX__CERTS_PATH}:/etc/nginx/certs:ro - ${NGINX__LOGS_PATH}:/var/log/nginx - - kelvin_app_static:/app/static + - app_static:/app/static:ro + - app_socket:/socket volumes: - kelvin_app_static: + app_static: + app_socket: diff --git a/nginx.conf b/nginx.conf deleted file mode 100644 index 26d2f744..00000000 --- a/nginx.conf +++ /dev/null @@ -1,51 +0,0 @@ -events { - worker_connections 1024; -} - -http { - - map $http_upgrade $connection_upgrade { - default upgrade; - '' close; - } - - - upstream django { - server kelvin_app:8000; # Uvicorn running Django app - } - - server { - listen 443 ssl; - server_name yourdomain.com; - - ssl_certificate /etc/nginx/certs/fullchain.pem; - ssl_certificate_key /etc/nginx/certs/privkey.pem; - - location / { - proxy_pass http://django; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; - - proxy_buffering off; - } - - # Serve static files - location /static/ { - autoindex on; - alias /app/static/; - include /etc/nginx/mime.types; - } - - } - - # Redirect all HTTP requests to HTTPS - server { - listen 80; - server_name yourdomain.com; - return 301 https://$host$request_uri; - } -} diff --git a/pyproject.toml b/pyproject.toml index b5fc1df7..f4d9bf7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,6 @@ dependencies = [ "typing-extensions==4.11.0", "Unidecode==1.3.6", "uWSGI==2.0.24", - "uvicorn[standard]>=0.30.6", ] [tool.uv] @@ -47,3 +46,20 @@ dev-dependencies = [ "pre-commit>=3.8.0", "ruff==0.6.3", ] + +[tool.ruff] +target-version = "py312" +line-length = 100 +indent-width = 4 + +include = [ + "api/**/*.py", + "common/**/*.py", + "evaluator/**/*.py", + "kelvin/**/*.py", + "survey/**/*.py", + "web/**/*.py" +] +extend-exclude = [ + "**/migrations/**" +] diff --git a/ruff.toml b/ruff.toml deleted file mode 100644 index 6c0d96d5..00000000 --- a/ruff.toml +++ /dev/null @@ -1,16 +0,0 @@ -include = [ - "api/**/*.py", - "common/**/*.py", - "evaluator/**/*.py", - "kelvin/**/*.py", - "survey/**/*.py", - "web/**/*.py" -] -exclude = [ - "**/migrations/**" -] - -line-length = 100 -indent-width = 4 - -target-version = "py312" diff --git a/uv.lock b/uv.lock index 1623618c..a12a2aa3 100644 --- a/uv.lock +++ b/uv.lock @@ -1,19 +1,6 @@ version = 1 requires-python = ">=3.12" -[[package]] -name = "anyio" -version = "4.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a0/44/66874c5256e9fbc30103b31927fd9341c8da6ccafd4721b2b3e81e6ef176/anyio-4.5.0.tar.gz", hash = "sha256:c5a275fe5ca0afd788001f58fca1e69e29ce706d746e317d660e21f70c530ef9", size = 169376 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/68/f9e9bf6324c46e6b8396610aef90ad423ec3e18c9079547ceafea3dce0ec/anyio-4.5.0-py3-none-any.whl", hash = "sha256:fdeb095b7cc5a5563175eedd926ec4ae55413bb4be5770c424af0ba46ccb4a78", size = 89250 }, -] - [[package]] name = "asgiref" version = "3.7.1" @@ -358,15 +345,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, ] -[[package]] -name = "h11" -version = "0.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, -] - [[package]] name = "http-ece" version = "1.2.0" @@ -376,21 +354,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/12/b5/bcbc98aa8d0c5f08e99136c801d05910858abc42ac9df17d3f58e730b4ab/http_ece-1.2.0.tar.gz", hash = "sha256:b5920f8efb8e1b5fb025713e3b36fda54336262010634b26dc1f98f85d1eb3de", size = 8771 } -[[package]] -name = "httptools" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/d77686502fced061b3ead1c35a2d70f6b281b5f723c4eff7a2277c04e4a2/httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a", size = 191228 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/13/b62e086b650752adf9094b7e62dab97f4cb7701005664544494b7956a51e/httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0", size = 146354 }, - { url = "https://files.pythonhosted.org/packages/f8/5d/9ad32b79b6c24524087e78aa3f0a2dfcf58c11c90e090e4593b35def8a86/httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2", size = 75785 }, - { url = "https://files.pythonhosted.org/packages/d0/a4/b503851c40f20bcbd453db24ed35d961f62abdae0dccc8f672cd5d350d87/httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90", size = 345396 }, - { url = "https://files.pythonhosted.org/packages/a2/9a/aa406864f3108e06f7320425a528ff8267124dead1fd72a3e9da2067f893/httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503", size = 344741 }, - { url = "https://files.pythonhosted.org/packages/cf/3a/3fd8dfb987c4247651baf2ac6f28e8e9f889d484ca1a41a9ad0f04dfe300/httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84", size = 345096 }, - { url = "https://files.pythonhosted.org/packages/80/01/379f6466d8e2edb861c1f44ccac255ed1f8a0d4c5c666a1ceb34caad7555/httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb", size = 343535 }, - { url = "https://files.pythonhosted.org/packages/d3/97/60860e9ee87a7d4712b98f7e1411730520053b9d69e9e42b0b9751809c17/httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949", size = 55660 }, -] - [[package]] name = "identify" version = "2.6.1" @@ -483,7 +446,6 @@ dependencies = [ { name = "six" }, { name = "typing-extensions" }, { name = "unidecode" }, - { name = "uvicorn", extra = ["standard"] }, { name = "uwsgi" }, ] @@ -527,7 +489,6 @@ requires-dist = [ { name = "six", specifier = "==1.16.0" }, { name = "typing-extensions", specifier = "==4.11.0" }, { name = "unidecode", specifier = "==1.3.6" }, - { name = "uvicorn", extras = ["standard"], specifier = ">=0.30.6" }, { name = "uwsgi", specifier = "==2.0.24" }, ] @@ -976,15 +937,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, ] -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, -] - [[package]] name = "soupsieve" version = "2.5" @@ -1079,44 +1031,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", size = 121444 }, ] -[[package]] -name = "uvicorn" -version = "0.30.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5a/01/5e637e7aa9dd031be5376b9fb749ec20b86f5a5b6a49b87fabd374d5fa9f/uvicorn-0.30.6.tar.gz", hash = "sha256:4b15decdda1e72be08209e860a1e10e92439ad5b97cf44cc945fcbee66fc5788", size = 42825 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/8e/cdc7d6263db313030e4c257dd5ba3909ebc4e4fb53ad62d5f09b1a2f5458/uvicorn-0.30.6-py3-none-any.whl", hash = "sha256:65fd46fe3fda5bdc1b03b94eb634923ff18cd35b2f084813ea79d1f103f711b5", size = 62835 }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.20.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/f1/dc9577455e011ad43d9379e836ee73f40b4f99c02946849a44f7ae64835e/uvloop-0.20.0.tar.gz", hash = "sha256:4603ca714a754fc8d9b197e325db25b2ea045385e8a3ad05d3463de725fdf469", size = 2329938 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/64/31cbd379d6e260ac8de3f672f904e924f09715c3f192b09f26cc8e9f574c/uvloop-0.20.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4b75f2950ddb6feed85336412b9a0c310a2edbcf4cf931aa5cfe29034829676d", size = 1324302 }, - { url = "https://files.pythonhosted.org/packages/1e/6b/9207e7177ff30f78299401f2e1163ea41130d4fd29bcdc6d12572c06b728/uvloop-0.20.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:77fbc69c287596880ecec2d4c7a62346bef08b6209749bf6ce8c22bbaca0239e", size = 738105 }, - { url = "https://files.pythonhosted.org/packages/c1/ba/b64b10f577519d875992dc07e2365899a1a4c0d28327059ce1e1bdfb6854/uvloop-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6462c95f48e2d8d4c993a2950cd3d31ab061864d1c226bbf0ee2f1a8f36674b9", size = 4090658 }, - { url = "https://files.pythonhosted.org/packages/0a/f8/5ceea6876154d926604f10c1dd896adf9bce6d55a55911364337b8a5ed8d/uvloop-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649c33034979273fa71aa25d0fe120ad1777c551d8c4cd2c0c9851d88fcb13ab", size = 4173357 }, - { url = "https://files.pythonhosted.org/packages/18/b2/117ab6bfb18274753fbc319607bf06e216bd7eea8be81d5bac22c912d6a7/uvloop-0.20.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a609780e942d43a275a617c0839d85f95c334bad29c4c0918252085113285b5", size = 4029868 }, - { url = "https://files.pythonhosted.org/packages/6f/52/deb4be09060637ef4752adaa0b75bf770c20c823e8108705792f99cd4a6f/uvloop-0.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aea15c78e0d9ad6555ed201344ae36db5c63d428818b4b2a42842b3870127c00", size = 4115980 }, -] - [[package]] name = "uwsgi" version = "2.0.24" @@ -1137,73 +1051,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/1d/e1a44fdd6d30829ba21fc58b5d98a67e7aae8f4165f11d091e53aec12560/virtualenv-20.26.5-py3-none-any.whl", hash = "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6", size = 5999288 }, ] -[[package]] -name = "watchfiles" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137 }, - { url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733 }, - { url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322 }, - { url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409 }, - { url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142 }, - { url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414 }, - { url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962 }, - { url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705 }, - { url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851 }, - { url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868 }, - { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 }, - { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 }, - { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 }, - { url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 }, - { url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 }, - { url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 }, - { url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 }, - { url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 }, - { url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 }, - { url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 }, - { url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 }, - { url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 }, - { url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 }, - { url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 }, - { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 }, -] - -[[package]] -name = "websockets" -version = "13.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8f/1c/78687e0267b09412409ac134f10fd14d14ac6475da892a8b09a02d0f6ae2/websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e", size = 149769 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/51/23ed2d239f1c3087c1431d41cfd159865df0bc35bb0c89973e3b6a0fff9b/websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a", size = 150953 }, - { url = "https://files.pythonhosted.org/packages/57/8d/814a7ef62b916b0f39108ad2e4d9b4cb0f8c640f8c30202fb63041598ada/websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956", size = 148610 }, - { url = "https://files.pythonhosted.org/packages/ad/8b/a378d21124011737e0e490a8a6ef778914b03e50c8d938de2f2170a20dbd/websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af", size = 148849 }, - { url = "https://files.pythonhosted.org/packages/46/d2/814a61226af313c1bc289cfe3a10f87bf426b6f2d9df0f927c47afab7612/websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf", size = 158772 }, - { url = "https://files.pythonhosted.org/packages/a1/7e/5987299eb7e131216c9027b05a65f149cbc2bde7c582e694d9eed6ec3d40/websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c", size = 157724 }, - { url = "https://files.pythonhosted.org/packages/94/6e/eaf95894042ba8a05a125fe8bcf9ee3572fef6edbcbf49478f4991c027cc/websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4", size = 158152 }, - { url = "https://files.pythonhosted.org/packages/ce/ba/a1315d569cc2dadaafda74a9cea16ab5d68142525937f1994442d969b306/websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab", size = 158442 }, - { url = "https://files.pythonhosted.org/packages/90/9b/59866695cfd05e785c90932fef3dae4682eb4e06e7076b7c53478f25faad/websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d", size = 157823 }, - { url = "https://files.pythonhosted.org/packages/9b/47/20af68a313b6453d2d094ccc497b7232e8475175d234e3e5bef5088521e5/websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237", size = 157818 }, - { url = "https://files.pythonhosted.org/packages/f8/bb/60aaedc80e388e978617dda1ff38788780c6b0f6e462b85368cb934131a5/websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185", size = 151785 }, - { url = "https://files.pythonhosted.org/packages/16/2e/e47692f569e1be2e66c1dbc5e85ea4d2cc93b80027fbafa28ae8b0dee52c/websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99", size = 152214 }, - { url = "https://files.pythonhosted.org/packages/46/37/d8ef4b68684d1fa368a5c64be466db07fc58b68163bc2496db2d4cc208ff/websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa", size = 150962 }, - { url = "https://files.pythonhosted.org/packages/95/49/78aeb3af08ec9887a9065e85cef9d7e199d6c6261fcd39eec087f3a62328/websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231", size = 148621 }, - { url = "https://files.pythonhosted.org/packages/31/0d/dc9b7cec8deaee452092a631ccda894bd7098859f71dd7639b4b5b9c615c/websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9", size = 148853 }, - { url = "https://files.pythonhosted.org/packages/16/bf/734cbd815d7bc94cffe35c934f4e08b619bf3b47df1c6c7af21c1d35bcfe/websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75", size = 158741 }, - { url = "https://files.pythonhosted.org/packages/af/9b/756f89b12fee8931785531a314e6f087b21774a7f8c60878e597c684f91b/websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553", size = 157690 }, - { url = "https://files.pythonhosted.org/packages/d3/37/31f97132d2262e666b797e250879ca833eab55115f88043b3952a2840eb8/websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920", size = 158132 }, - { url = "https://files.pythonhosted.org/packages/41/ce/59c8d44e148c002fec506a9527504fb4281676e2e75c2ee5a58180f1b99a/websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329", size = 158490 }, - { url = "https://files.pythonhosted.org/packages/1a/74/5b31ce0f318b902c0d70c031f8e1228ba1a4d95a46b2a24a2a5ac17f9cf0/websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7", size = 157879 }, - { url = "https://files.pythonhosted.org/packages/0d/a7/6eac4f04177644bbc98deb98d11770cc7fbc216f6f67ab187c150540fd52/websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2", size = 157873 }, - { url = "https://files.pythonhosted.org/packages/72/f6/b8b30a3b134dfdb4ccd1694befa48fddd43783957c988a1dab175732af33/websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb", size = 151782 }, - { url = "https://files.pythonhosted.org/packages/3e/88/d94ccc006c69583168aa9dd73b3f1885c8931f2c676f4bdd8cbfae91c7b6/websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b", size = 152212 }, - { url = "https://files.pythonhosted.org/packages/fd/bd/d34c4b7918453506d2149208b175368738148ffc4ba256d7fd8708956732/websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817", size = 145262 }, -] - [[package]] name = "wrapt" version = "1.16.0" From 501818862ed3c84cf60c7ab317c7c2b61aa99cfe Mon Sep 17 00:00:00 2001 From: JersyJ Date: Fri, 4 Oct 2024 22:59:21 +0200 Subject: [PATCH 10/12] Add local_settings.py --- deploy/local_settings.py | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 deploy/local_settings.py diff --git a/deploy/local_settings.py b/deploy/local_settings.py new file mode 100644 index 00000000..216c5da8 --- /dev/null +++ b/deploy/local_settings.py @@ -0,0 +1,3 @@ +# This file can be used to override settings for deployment +# e.g. +# DEBUG=False From e6b20c95ad5881dfd052817cdef1daad71410607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 5 Oct 2024 15:42:26 +0200 Subject: [PATCH 11/12] Synchronize `requirements.txt` --- requirements.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/requirements.txt b/requirements.txt index e4a511d3..c3c11f13 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,6 +28,9 @@ cffi==1.16.0 ; platform_python_implementation != 'PyPy' \ --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 +cfgv==3.4.0 \ + --hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560 \ + --hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 charset-normalizer==3.3.2 \ --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ @@ -89,6 +92,9 @@ decorator==5.1.1 \ deprecated==1.2.14 \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c +distlib==0.3.8 \ + --hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64 \ + --hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 django==4.2.16 \ --hash=sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad \ --hash=sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898 @@ -114,8 +120,14 @@ django-webpush==0.3.4 \ --hash=sha256:28cbe7da20f1df5b61d859f61e2d11d4076de1c367aa048d654894fb8f324065 \ --hash=sha256:a123102dede1a959f667e075ed746ac5b7d4a8622320162eba41a507a835e1e4 \ --hash=sha256:a2613784e822e2dde27086fb20b6d1a2b76e4d5dc8271607aecd45c98a3b7954 +filelock==3.16.1 \ + --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 \ + --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 http-ece==1.2.0 \ --hash=sha256:b5920f8efb8e1b5fb025713e3b36fda54336262010634b26dc1f98f85d1eb3de +identify==2.6.1 \ + --hash=sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98 \ + --hash=sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0 idna==3.6 \ --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \ --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f @@ -153,6 +165,9 @@ mypy-extensions==1.0.0 \ networkx==2.5 \ --hash=sha256:7978955423fbc9639c10498878be59caf99b44dc304c2286162fd24b458c1602 \ --hash=sha256:8c5812e9f798d37c50570d15c4a69d5710a18d77bafc903ee9c5fba7454c616c +nodeenv==1.9.1 \ + --hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \ + --hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9 numpy==1.26.4 \ --hash=sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010 \ --hash=sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218 \ @@ -191,9 +206,15 @@ pillow==10.2.0 \ --hash=sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f \ --hash=sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9 \ --hash=sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48 +platformdirs==4.3.6 \ + --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ + --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb plum-dispatch==2.2.2 \ --hash=sha256:d5d180225c9fbf0277375bb558b649d97d0b651a91037bb7155cedbe9f52764b \ --hash=sha256:d7ee415bd166ffa90eaa4b24d7c9dc7ca6f8875750586001e7c9baff706223bd +pre-commit==3.8.0 \ + --hash=sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af \ + --hash=sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f psycopg==3.2.1 \ --hash=sha256:dc8da6dc8729dacacda3cc2f17d2c9397a70a66cf0d2b69c91065d60d5f00cb7 \ --hash=sha256:ece385fb413a37db332f97c49208b36cf030ff02b199d7635ed2fbd378724175 @@ -320,6 +341,9 @@ urllib3==2.2.2 \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 uwsgi==2.0.24 \ --hash=sha256:77b6dd5cd633f4ae87ee393f7701f617736815499407376e78f3d16467523afe +virtualenv==20.26.5 \ + --hash=sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4 \ + --hash=sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6 wrapt==1.16.0 \ --hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \ --hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \ From d197687583dd016e8c6ae696d9a7efd90d7e68e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 5 Oct 2024 15:48:18 +0200 Subject: [PATCH 12/12] Remove asgi.py It should not be needed at the moment. --- kelvin/asgi.py | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 kelvin/asgi.py diff --git a/kelvin/asgi.py b/kelvin/asgi.py deleted file mode 100644 index d274e2c6..00000000 --- a/kelvin/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for kelvin 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", "kelvin.settings") - -application = get_asgi_application()