build fixes and static files fix, closes #28
This commit is contained in:
parent
bff2525c65
commit
6a44ef30a3
26 changed files with 91 additions and 39 deletions
20
Dockerfile
20
Dockerfile
|
|
@ -1,14 +1,12 @@
|
||||||
# Pull base image
|
|
||||||
FROM python:3.12.2-bookworm
|
FROM python:3.12.2-bookworm
|
||||||
|
|
||||||
# Set environment variables (we want to write bytecode as we have multiple workers, so omit PYTHONDONTWRITEBYTECODE)
|
# (we want to write bytecode as we have multiple workers, so omit PYTHONDONTWRITEBYTECODE)
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
ENV HOME /code
|
||||||
|
|
||||||
# Create and set work directory called `app`
|
|
||||||
RUN mkdir -p /code
|
RUN mkdir -p /code
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
COPY requirements.txt /tmp/requirements.txt
|
COPY requirements.txt /tmp/requirements.txt
|
||||||
|
|
||||||
RUN set -ex && \
|
RUN set -ex && \
|
||||||
|
|
@ -16,20 +14,16 @@ RUN set -ex && \
|
||||||
pip install -r /tmp/requirements.txt && \
|
pip install -r /tmp/requirements.txt && \
|
||||||
rm -rf /root/.cache/
|
rm -rf /root/.cache/
|
||||||
|
|
||||||
# Copy local project
|
|
||||||
COPY . /code/
|
|
||||||
COPY .env.production /code/.env
|
|
||||||
ENV HOME=/code
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y nodejs npm xvfb netcat-openbsd nano curl
|
RUN apt-get update && apt-get install -y nodejs npm xvfb netcat-openbsd nano curl
|
||||||
|
|
||||||
# Install playwright (via pip and install script)
|
|
||||||
RUN playwright install-deps && playwright install
|
RUN playwright install-deps && playwright install
|
||||||
|
|
||||||
# Expose port 8000
|
COPY . /code/
|
||||||
|
COPY .env.production /code/.env
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1
|
HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1
|
||||||
|
|
||||||
# Use gunicorn on port 8000
|
#CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--workers", "3", "--worker-class", "gevent", "--worker-connections", "1000", "--worker-tmp-dir", "/dev/shm", "--timeout", "90"]
|
||||||
CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--workers", "4", "--worker-tmp-dir", "/dev/shm", "--timeout", "90"]
|
CMD ["granian", "--interface", "wsgi", "django_project.wsgi", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
python manage.py migrate --noinput
|
python manage.py migrate --noinput
|
||||||
python manage.py clear_cache
|
python manage.py clear_cache
|
||||||
python manage.py collectstatic --noinput
|
python manage.py collectstatic -c --no-input
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
from accounts.models import CustomUser
|
import time
|
||||||
from django.contrib.auth.models import User
|
import logging
|
||||||
class AutoLoginMiddleware:
|
class LogRequestsMiddleware:
|
||||||
"""
|
|
||||||
In development, automatically logs in as a predefined user if the request is anonymous.
|
|
||||||
"""
|
|
||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
# Only perform auto-login if in DEBUG mode and user is not authenticated.
|
start = time.perf_counter()
|
||||||
if settings.DEBUG and not request.user.is_authenticated and request.host in ['pocket-trade.fly.dev', 'localhost', '127.0.0.1']:
|
|
||||||
user = CustomUser.objects.get(email='rob@badblocks.email')
|
|
||||||
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
|
|
||||||
|
|
||||||
response = self.get_response(request)
|
response = self.get_response(request)
|
||||||
|
end = time.perf_counter()
|
||||||
|
self.log(request, response, start, end)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def log(self, request, response, start, end):
|
||||||
|
logging.info(f"{request.method} {request.path_info} -> {response.status_code}, took {end - start}s")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,48 @@ import socket
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import environ
|
import environ
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
env = environ.Env(
|
env = environ.Env(
|
||||||
DEBUG=(bool, False)
|
DEBUG=(bool, False)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LOGGING = {
|
||||||
|
'version': 1,
|
||||||
|
'disable_existing_loggers': False,
|
||||||
|
'formatters': {
|
||||||
|
'verbose': {
|
||||||
|
'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'console': {
|
||||||
|
'level': 'INFO',
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'stream': sys.stdout,
|
||||||
|
'formatter': 'verbose',
|
||||||
|
'filters': [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'loggers': {
|
||||||
|
'django': {
|
||||||
|
'handlers': ['console'],
|
||||||
|
'level': 'INFO',
|
||||||
|
},
|
||||||
|
'django.server': {
|
||||||
|
'handlers': ['console'],
|
||||||
|
'level': 'INFO',
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
|
'': {
|
||||||
|
'handlers': ['console'],
|
||||||
|
'level': 'INFO',
|
||||||
|
'propagate': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
@ -80,10 +117,12 @@ MIDDLEWARE = [
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"allauth.account.middleware.AccountMiddleware", # django-allauth
|
"allauth.account.middleware.AccountMiddleware", # django-allauth
|
||||||
|
"django_project.middleware.LogRequestsMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
MIDDLEWARE.append("django_browser_reload.middleware.BrowserReloadMiddleware")
|
MIDDLEWARE.append(
|
||||||
|
"django_browser_reload.middleware.BrowserReloadMiddleware")
|
||||||
MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware")
|
MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware")
|
||||||
|
|
||||||
DAISY_SETTINGS = {
|
DAISY_SETTINGS = {
|
||||||
|
|
@ -164,7 +203,7 @@ STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||||
STATIC_URL = "/static/"
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
||||||
STATICFILES_DIRS = []
|
STATICFILES_DIRS = [BASE_DIR / "static"]
|
||||||
|
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#media-root
|
# https://docs.djangoproject.com/en/dev/ref/settings/#media-root
|
||||||
MEDIA_ROOT = BASE_DIR / "media"
|
MEDIA_ROOT = BASE_DIR / "media"
|
||||||
|
|
@ -211,7 +250,9 @@ INTERNAL_IPS = [
|
||||||
|
|
||||||
# for docker development
|
# for docker development
|
||||||
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
||||||
INTERNAL_IPS.append([ip[:-1] + "1" for ip in ips])
|
for ip in ips:
|
||||||
|
INTERNAL_IPS.append(ip)
|
||||||
|
ALLOWED_HOSTS.append(ip)
|
||||||
|
|
||||||
# https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model
|
# https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model
|
||||||
AUTH_USER_MODEL = "accounts.CustomUser"
|
AUTH_USER_MODEL = "accounts.CustomUser"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ urlpatterns = [
|
||||||
path('account/', include('accounts.urls')),
|
path('account/', include('accounts.urls')),
|
||||||
path("trades/", include("trades.urls")),
|
path("trades/", include("trades.urls")),
|
||||||
path("__reload__/", include("django_browser_reload.urls")),
|
path("__reload__/", include("django_browser_reload.urls")),
|
||||||
#path('silk/', include('silk.urls', namespace='silk')),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@ from django.core.wsgi import get_wsgi_application
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings")
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
app = application
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
command: python /code/manage.py runserver 0.0.0.0:8000
|
#command: python /code/manage.py runserver 0.0.0.0:8000
|
||||||
volumes:
|
volumes:
|
||||||
- .:/code:z
|
- .:/code:z
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
12
fly.toml
12
fly.toml
|
|
@ -12,6 +12,7 @@ console_command = '/code/manage.py shell'
|
||||||
|
|
||||||
[deploy]
|
[deploy]
|
||||||
release_command = 'bash deploy.sh'
|
release_command = 'bash deploy.sh'
|
||||||
|
strategy = 'bluegreen'
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
PORT = '8000'
|
PORT = '8000'
|
||||||
|
|
@ -24,9 +25,16 @@ console_command = '/code/manage.py shell'
|
||||||
min_machines_running = 0
|
min_machines_running = 0
|
||||||
processes = ['app']
|
processes = ['app']
|
||||||
|
|
||||||
|
[[http_service.checks]]
|
||||||
|
grace_period = "15s"
|
||||||
|
interval = "30s"
|
||||||
|
method = "GET"
|
||||||
|
timeout = "10s"
|
||||||
|
path = "/health"
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
size = 'shared-cpu-4x'
|
size = 'shared-cpu-8x'
|
||||||
memory = '1gb'
|
memory = '2gb'
|
||||||
|
|
||||||
[[statics]]
|
[[statics]]
|
||||||
guest_path = '/code/static'
|
guest_path = '/code/static'
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from .views import HomePageView
|
from .views import HomePageView, HealthCheckView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", HomePageView.as_view(), name="home"),
|
path("", HomePageView.as_view(), name="home"),
|
||||||
|
path("health", HealthCheckView.as_view(), name="health"),
|
||||||
|
path("health/", HealthCheckView.as_view(), name="health"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ from django.utils.decorators import method_decorator
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
import logging
|
import logging
|
||||||
#from silk.profiling.profiler import silk_profile
|
from django.views import View
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -114,3 +115,7 @@ class HomePageView(TemplateView):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
"""Override get method to add caching"""
|
"""Override get method to add caching"""
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
class HealthCheckView(View):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return HttpResponse("OK/HEALTHY")
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ docker compose -f docker-compose_db_only.yml down \
|
||||||
echo "Waiting for the database to be ready..."
|
echo "Waiting for the database to be ready..."
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
|
echo "Resetting static files..."
|
||||||
|
uv run python manage.py collectstatic -c --no-input
|
||||||
|
|
||||||
echo "Running makemigrations..."
|
echo "Running makemigrations..."
|
||||||
uv run python manage.py makemigrations
|
uv run python manage.py makemigrations
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 549 B After Width: | Height: | Size: 549 B |
|
|
@ -25,12 +25,12 @@
|
||||||
</a>
|
</a>
|
||||||
<!-- Main Card Row: Single row with the acceptance's cards -->
|
<!-- Main Card Row: Single row with the acceptance's cards -->
|
||||||
<div class="px-2 pb-0">
|
<div class="px-2 pb-0">
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center gap-2">
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<div class="cursor-pointer">{% card_badge acceptance.requested_card %}</div>
|
{% card_badge acceptance.requested_card %}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<div class="cursor-pointer">{% card_badge acceptance.offered_card %}</div>
|
{% card_badge acceptance.offered_card %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue