From 288759146cf8c82bba7bfe277d4e5a5f8151a8cf Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 10:51:57 +0000 Subject: [PATCH 01/10] Clean images and case insensitive nav. --- .../primary/migrations/0010_page_prority.py | 18 ++++++++++++++++++ .../0011_rename_prority_page_priority.py | 18 ++++++++++++++++++ wedding_site/primary/models.py | 1 + wedding_site/primary/static/primary/style.css | 7 +++++-- wedding_site/primary/views.py | 15 ++++++++++++++- wedding_site/wedding_site/settings.py | 2 +- wedding_site/wedding_site/urls.py | 2 ++ 7 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 wedding_site/primary/migrations/0010_page_prority.py create mode 100644 wedding_site/primary/migrations/0011_rename_prority_page_priority.py diff --git a/wedding_site/primary/migrations/0010_page_prority.py b/wedding_site/primary/migrations/0010_page_prority.py new file mode 100644 index 0000000..01223ed --- /dev/null +++ b/wedding_site/primary/migrations/0010_page_prority.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-02-18 09:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('primary', '0009_page_pretty_name'), + ] + + operations = [ + migrations.AddField( + model_name='page', + name='prority', + field=models.IntegerField(default=0), + ), + ] diff --git a/wedding_site/primary/migrations/0011_rename_prority_page_priority.py b/wedding_site/primary/migrations/0011_rename_prority_page_priority.py new file mode 100644 index 0000000..42ac5dd --- /dev/null +++ b/wedding_site/primary/migrations/0011_rename_prority_page_priority.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-02-18 10:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('primary', '0010_page_prority'), + ] + + operations = [ + migrations.RenameField( + model_name='page', + old_name='prority', + new_name='priority', + ), + ] diff --git a/wedding_site/primary/models.py b/wedding_site/primary/models.py index a73c009..ac7603e 100644 --- a/wedding_site/primary/models.py +++ b/wedding_site/primary/models.py @@ -18,6 +18,7 @@ class Page(models.Model): pretty_name = models.CharField(max_length=200, default="") published = models.BooleanField(default=False) navigable = models.BooleanField(default=False) + priority = models.IntegerField(default=0) def __str__(self): return self.name diff --git a/wedding_site/primary/static/primary/style.css b/wedding_site/primary/static/primary/style.css index 8384158..bbd73c0 100755 --- a/wedding_site/primary/static/primary/style.css +++ b/wedding_site/primary/static/primary/style.css @@ -33,10 +33,9 @@ body { img { margin:0 auto; - width: 100%; display: flex; justify-content: center; - max-height:300px; + max-width:800px; border-radius: 8px; box-shadow: 0 4px 8px 0; } @@ -107,6 +106,10 @@ ul { list-style-position: inside; } +ul li { + padding: 5px 0px; +} + .login-input{ margin-top: 30px; text-align: center; diff --git a/wedding_site/primary/views.py b/wedding_site/primary/views.py index f9295ff..6a90d8f 100644 --- a/wedding_site/primary/views.py +++ b/wedding_site/primary/views.py @@ -6,6 +6,8 @@ from django.template import Context from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import login_required +from django.views.defaults import page_not_found + import markdown from bs4 import BeautifulSoup @@ -24,6 +26,17 @@ _TEMPLATE = """ """ +def handler404(request, exception, template_name="404.html"): + page_names = ["home", "schedule", "thingstodo"] + working_path = request.path.lower() + if working_path and working_path[0] == "/": + working_path = working_path[1:] + if working_path and working_path[-1] == "/": + working_path = working_path[:-1] + if working_path in page_names: + return redirect(working_path) + return page_not_found(request, exception, template_name) + def get_site_header(site): template = Template(site.header) context = Context({"site": site}) @@ -60,7 +73,7 @@ def home(request): def get_page_header(site: Site): - pages = site.page_set.filter(navigable=True) + pages = site.page_set.order_by("priority").filter(navigable=True) template = Template(site.page_header) context = Context({"pages" : pages}) return template.render(context) diff --git a/wedding_site/wedding_site/settings.py b/wedding_site/wedding_site/settings.py index c43b4ba..d97a4d7 100644 --- a/wedding_site/wedding_site/settings.py +++ b/wedding_site/wedding_site/settings.py @@ -25,7 +25,7 @@ SECRET_KEY = 'django-insecure-bj9fez3qztt5e2lrzpgh%%nat@w^kn!k@l92l=+#%wm)4)p^5m # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["localhost"] # Application definition diff --git a/wedding_site/wedding_site/urls.py b/wedding_site/wedding_site/urls.py index 6528297..539927f 100644 --- a/wedding_site/wedding_site/urls.py +++ b/wedding_site/wedding_site/urls.py @@ -23,3 +23,5 @@ urlpatterns = [ path("", include('primary.urls')), path('admin/', admin.site.urls), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + +handler404 = 'primary.views.handler404' From 9576202fa1cc2dc24087c9733986777517e04901 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 14:09:12 +0000 Subject: [PATCH 02/10] Start adding deployment infra. --- .gitignore | 2 ++ README.md | 33 ++++++++++++++++++++++++--- compose.prod.yaml | 25 ++++++++++++++++++++ compose.yaml | 12 ++++++++++ infra/install_arch_deps.sh | 1 + nginx/Dockerfile | 4 ++++ nginx/nginx.conf | 20 ++++++++++++++++ requirements.txt | 5 +--- wedding_site/Dockerfile | 16 +++++++++++++ wedding_site/requirements.txt | 5 ++++ wedding_site/wedding_site/settings.py | 10 ++++---- 11 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 compose.prod.yaml create mode 100644 compose.yaml create mode 100644 infra/install_arch_deps.sh create mode 100644 nginx/Dockerfile create mode 100644 nginx/nginx.conf create mode 100644 wedding_site/Dockerfile create mode 100644 wedding_site/requirements.txt diff --git a/.gitignore b/.gitignore index e1dba2e..041559f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ /build */uploads +*/staticfiles __pycache__ *.pyc .venv +.env* *.sqlite3 diff --git a/README.md b/README.md index d7112f5..8ead6d7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Web backend for hosting a wedding website. -## Run development server: +# Run Local server: ```sh source .venv/bin/activate @@ -10,10 +10,37 @@ cd wedding_site python manage.py runserver ``` -## Do Migrations +# Do Migrations ```sh cd wedding_site python manage.py makemigrations primary python manage.py migrate -``` \ No newline at end of file +``` + +# Run Dev Server in container + +```sh +podman-compose -f compose.yaml up -d --build +``` + +Bring it down with: + +```sh +podman-compose down -v +``` + +# Run Prod Server + +```sh +podman-compose -f compose.prod.yaml up -d --build +``` + +Sync static files: + +```sh +podman-compose -f compose.prod.yaml exec web python manage.py collectstatic --no-input --clear +``` + + + diff --git a/compose.prod.yaml b/compose.prod.yaml new file mode 100644 index 0000000..f406dfd --- /dev/null +++ b/compose.prod.yaml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + web: + build: ./wedding_site + command: gunicorn wedding_site.wsgi:application --bind 0.0.0.0:8000 + volumes: + - ./wedding_site/:/usr/src/app/ + - static_volume:/staticfiles + expose: + - 8000 + env_file: + - ./.env.prod + + nginx: + build: ./nginx + ports: + - 8080:80 + volumes: + - static_volume:/staticfiles + depends_on: + - web + +volumes: + static_volume: \ No newline at end of file diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..ddaa801 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,12 @@ +version: '3.8' + +services: + web: + build: ./wedding_site + command: python manage.py runserver 0.0.0.0:8000 + volumes: + - ./wedding_site/:/usr/src/app/ + ports: + - 8000:8000 + env_file: + - ./.env.dev \ No newline at end of file diff --git a/infra/install_arch_deps.sh b/infra/install_arch_deps.sh new file mode 100644 index 0000000..8937870 --- /dev/null +++ b/infra/install_arch_deps.sh @@ -0,0 +1 @@ +pacman -Sy podman aardvark-dns \ No newline at end of file diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..bdde282 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,4 @@ +FROM docker.io/nginx + +RUN rm /etc/nginx/conf.d/default.conf +COPY nginx.conf /etc/nginx/conf.d \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..10a320d --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,20 @@ +upstream wedding_site { + server web:8000; +} + +server { + + listen 80; + + location / { + proxy_pass http://wedding_site; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_redirect off; + } + + location /static/ { + alias /staticfiles/; + } + +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2e2e3ab..e7584bd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1 @@ -django -markdown -pillow -beautifulsoup4 +podman-compose \ No newline at end of file diff --git a/wedding_site/Dockerfile b/wedding_site/Dockerfile new file mode 100644 index 0000000..7817462 --- /dev/null +++ b/wedding_site/Dockerfile @@ -0,0 +1,16 @@ +# pull official base image +FROM python:3.11.4-slim-buster + +# set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# install dependencies +RUN pip install --upgrade pip +COPY ./requirements.txt . +RUN pip install -r requirements.txt + +RUN mkdir staticfiles + +# copy project +COPY . . \ No newline at end of file diff --git a/wedding_site/requirements.txt b/wedding_site/requirements.txt new file mode 100644 index 0000000..2666a26 --- /dev/null +++ b/wedding_site/requirements.txt @@ -0,0 +1,5 @@ +django +markdown +pillow +beautifulsoup4 +gunicorn \ No newline at end of file diff --git a/wedding_site/wedding_site/settings.py b/wedding_site/wedding_site/settings.py index d97a4d7..aaf44cc 100644 --- a/wedding_site/wedding_site/settings.py +++ b/wedding_site/wedding_site/settings.py @@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.0/ref/settings/ """ from pathlib import Path +import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -19,13 +20,11 @@ BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-bj9fez3qztt5e2lrzpgh%%nat@w^kn!k@l92l=+#%wm)4)p^5m' +SECRET_KEY = os.environ.get("SECRET_KEY") -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = bool(os.environ.get("DEBUG", default=0)) -ALLOWED_HOSTS = ["localhost"] +ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") # Application definition @@ -117,6 +116,7 @@ USE_TZ = True # https://docs.djangoproject.com/en/5.0/howto/static-files/ STATIC_URL = 'static/' +STATIC_ROOT = BASE_DIR / "staticfiles" # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field From 2b9dbcbb2d7f686ee9d111ffaf02636ef88479e9 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 14:25:20 +0000 Subject: [PATCH 03/10] Handle media files. --- compose.prod.yaml | 5 ++++- nginx/nginx.conf | 5 +++++ wedding_site/Dockerfile | 3 +++ wedding_site/wedding_site/settings.py | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compose.prod.yaml b/compose.prod.yaml index f406dfd..033f7f8 100644 --- a/compose.prod.yaml +++ b/compose.prod.yaml @@ -7,6 +7,7 @@ services: volumes: - ./wedding_site/:/usr/src/app/ - static_volume:/staticfiles + - media_volume:/mediafiles expose: - 8000 env_file: @@ -18,8 +19,10 @@ services: - 8080:80 volumes: - static_volume:/staticfiles + - media_volume:/mediafiles depends_on: - web volumes: - static_volume: \ No newline at end of file + static_volume: + media_volume: \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 10a320d..831bbbe 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -11,10 +11,15 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_redirect off; + client_max_body_size 100M; } location /static/ { alias /staticfiles/; } + location /media/ { + alias /mediafiles/; + } + } \ No newline at end of file diff --git a/wedding_site/Dockerfile b/wedding_site/Dockerfile index 7817462..ded2fa5 100644 --- a/wedding_site/Dockerfile +++ b/wedding_site/Dockerfile @@ -11,6 +11,9 @@ COPY ./requirements.txt . RUN pip install -r requirements.txt RUN mkdir staticfiles +RUN mkdir mediafiles + +ADD ./uploads /mediafiles # copy project COPY . . \ No newline at end of file diff --git a/wedding_site/wedding_site/settings.py b/wedding_site/wedding_site/settings.py index aaf44cc..b9992ed 100644 --- a/wedding_site/wedding_site/settings.py +++ b/wedding_site/wedding_site/settings.py @@ -118,6 +118,9 @@ USE_TZ = True STATIC_URL = 'static/' STATIC_ROOT = BASE_DIR / "staticfiles" +MEDIA_URL = 'media/' +MEDIA_ROOT = BASE_DIR / "mediafiles" + # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field From 03778e9834998386179455a6bcac073bb5320f96 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 14:33:44 +0000 Subject: [PATCH 04/10] Fix missing images. --- wedding_site/primary/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wedding_site/primary/views.py b/wedding_site/primary/views.py index 6a90d8f..b0d285b 100644 --- a/wedding_site/primary/views.py +++ b/wedding_site/primary/views.py @@ -100,7 +100,8 @@ def get_page(name:str): img_name = img["src"] db_images = Image.objects.filter(name=img_name) if db_images: - img["src"] = db_images[0].content.url + url = db_images[0].content.url.replace("uploads/","") + img["src"] = url return HttpResponse(soup.prettify()) From 4be5e93c9c5621550a5c50269d46ecc5a19e546a Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 15:04:22 +0000 Subject: [PATCH 05/10] Start adding virtual sites with nginx. --- compose.staging.yaml | 52 ++++++++++++++++++ nginx/Dockerfile | 7 +-- nginx/custom.conf | 1 + nginx/nginx.conf | 25 --------- nginx/vhost.d/default | 9 +++ .../primary/static/primary/favicon.ico | Bin 0 -> 15406 bytes wedding_site/wedding_site/settings.py | 3 + 7 files changed, 68 insertions(+), 29 deletions(-) create mode 100644 compose.staging.yaml create mode 100644 nginx/custom.conf delete mode 100644 nginx/nginx.conf create mode 100644 nginx/vhost.d/default create mode 100755 wedding_site/primary/static/primary/favicon.ico diff --git a/compose.staging.yaml b/compose.staging.yaml new file mode 100644 index 0000000..a81bdc3 --- /dev/null +++ b/compose.staging.yaml @@ -0,0 +1,52 @@ +version: '3.8' + +services: + web: + build: ./wedding_site + command: gunicorn wedding_site.wsgi:application --bind 0.0.0.0:8000 + volumes: + - ./wedding_site/:/usr/src/app/ + - static_volume:/staticfiles + - media_volume:/mediafiles + expose: + - 8000 + env_file: + - ./.env.staging + + nginx-proxy: + container_name: nginx-proxy + build: ./nginx + restart: always + ports: + - 443:443 + - 8080:80 + volumes: + - static_volume:/staticfiles + - media_volume:/mediafiles + - certs:/etc/nginx/certs + - html:/usr/share/nginx/html + - vhost:/etc/nginx/vhost.d + - /var/run/docker.sock:/tmp/docker/sock:ro + depends_on: + - web + + acme-companion: + image: nginxproxy/acme-companion + env_file: + - ./.env.staging.proxy-companion + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - certs:/etc/nginx/certs + - html:/usr/share/nginx/html + - vhost:/etc/nginx/vhost.d + - acme:/etc/acme.sh + depends_on: + - nginx-proxy + +volumes: + static_volume: + media_volume: + certs: + html: + vhost: + acme: \ No newline at end of file diff --git a/nginx/Dockerfile b/nginx/Dockerfile index bdde282..e2f0ed0 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,4 +1,3 @@ -FROM docker.io/nginx - -RUN rm /etc/nginx/conf.d/default.conf -COPY nginx.conf /etc/nginx/conf.d \ No newline at end of file +FROM docker.io/nginxproxy/nginx-proxy +COPY vhost.d/default /etc/nginx/vhost.d/default +COPY custom.conf /etc/nginx/conf.d/custom.conf \ No newline at end of file diff --git a/nginx/custom.conf b/nginx/custom.conf new file mode 100644 index 0000000..e9a5e8e --- /dev/null +++ b/nginx/custom.conf @@ -0,0 +1 @@ +client_max_body_size 100M; \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf deleted file mode 100644 index 831bbbe..0000000 --- a/nginx/nginx.conf +++ /dev/null @@ -1,25 +0,0 @@ -upstream wedding_site { - server web:8000; -} - -server { - - listen 80; - - location / { - proxy_pass http://wedding_site; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $host; - proxy_redirect off; - client_max_body_size 100M; - } - - location /static/ { - alias /staticfiles/; - } - - location /media/ { - alias /mediafiles/; - } - -} \ No newline at end of file diff --git a/nginx/vhost.d/default b/nginx/vhost.d/default new file mode 100644 index 0000000..bd8fd4d --- /dev/null +++ b/nginx/vhost.d/default @@ -0,0 +1,9 @@ +location /static/ { + alias /staticfiles/; + add_header Access-Control-Allow-Origin *; +} + +location /media/ { + alias /mediafiles/; + add_header Access-Control-Allow-Origin *; +} \ No newline at end of file diff --git a/wedding_site/primary/static/primary/favicon.ico b/wedding_site/primary/static/primary/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..115ea84d02d174299ba286b23348448610b6c15b GIT binary patch literal 15406 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 Q0=o-;#`tBlfF2h39}82@E&u=k literal 0 HcmV?d00001 diff --git a/wedding_site/wedding_site/settings.py b/wedding_site/wedding_site/settings.py index b9992ed..33eb86b 100644 --- a/wedding_site/wedding_site/settings.py +++ b/wedding_site/wedding_site/settings.py @@ -111,6 +111,9 @@ USE_I18N = True USE_TZ = True +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") +CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split(" ") + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ From 7ba077608c03c917c73b8bccee8c7567087db0cd Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 17:20:38 +0000 Subject: [PATCH 06/10] Get site running on staging domain. --- compose.prod.yaml | 30 +++++++++++++++++++--- compose.staging.yaml | 6 ++--- nginx/Dockerfile | 1 + wedding_site/primary/templates/header.html | 1 + wedding_site/wedding_site/settings.py | 22 ++++++++++++---- 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/compose.prod.yaml b/compose.prod.yaml index 033f7f8..a60429c 100644 --- a/compose.prod.yaml +++ b/compose.prod.yaml @@ -13,16 +13,40 @@ services: env_file: - ./.env.prod - nginx: + nginx-proxy: + container_name: nginx-proxy build: ./nginx + restart: always ports: - - 8080:80 + - 443:443 + - 80:80 volumes: - static_volume:/staticfiles - media_volume:/mediafiles + - certs:/etc/nginx/certs + - html:/usr/share/nginx/html + - vhost:/etc/nginx/vhost.d + - /var/run/docker.sock:/tmp/docker.sock:ro depends_on: - web + acme-companion: + image: docker.io/nginxproxy/acme-companion + env_file: + - ./.env.prod.proxy-companion + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - certs:/etc/nginx/certs + - html:/usr/share/nginx/html + - vhost:/etc/nginx/vhost.d + - acme:/etc/acme.sh + depends_on: + - nginx-proxy + volumes: static_volume: - media_volume: \ No newline at end of file + media_volume: + certs: + html: + vhost: + acme: \ No newline at end of file diff --git a/compose.staging.yaml b/compose.staging.yaml index a81bdc3..5d151a9 100644 --- a/compose.staging.yaml +++ b/compose.staging.yaml @@ -19,19 +19,19 @@ services: restart: always ports: - 443:443 - - 8080:80 + - 80:80 volumes: - static_volume:/staticfiles - media_volume:/mediafiles - certs:/etc/nginx/certs - html:/usr/share/nginx/html - vhost:/etc/nginx/vhost.d - - /var/run/docker.sock:/tmp/docker/sock:ro + - /var/run/docker.sock:/tmp/docker.sock:ro depends_on: - web acme-companion: - image: nginxproxy/acme-companion + image: docker.io/nginxproxy/acme-companion env_file: - ./.env.staging.proxy-companion volumes: diff --git a/nginx/Dockerfile b/nginx/Dockerfile index e2f0ed0..98aa030 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,3 +1,4 @@ FROM docker.io/nginxproxy/nginx-proxy + COPY vhost.d/default /etc/nginx/vhost.d/default COPY custom.conf /etc/nginx/conf.d/custom.conf \ No newline at end of file diff --git a/wedding_site/primary/templates/header.html b/wedding_site/primary/templates/header.html index 6574036..32bb550 100644 --- a/wedding_site/primary/templates/header.html +++ b/wedding_site/primary/templates/header.html @@ -3,4 +3,5 @@ content="width=device-width, initial-scale=1"> {% load static %} + \ No newline at end of file diff --git a/wedding_site/wedding_site/settings.py b/wedding_site/wedding_site/settings.py index 33eb86b..b7e5b95 100644 --- a/wedding_site/wedding_site/settings.py +++ b/wedding_site/wedding_site/settings.py @@ -22,9 +22,11 @@ BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = os.environ.get("SECRET_KEY") -DEBUG = bool(os.environ.get("DEBUG", default=0)) +#DEBUG = bool(os.environ.get("DEBUG", default=0)) +#DEBUG=True -ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") +if "DJANGO_ALLOWED_HOSTS" in os.environ: + ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") # Application definition @@ -112,17 +114,27 @@ USE_I18N = True USE_TZ = True SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") -CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split(" ") + +if "CSRF_TRUSTED_ORIGINS" in os.environ: + CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split(" ") # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ STATIC_URL = 'static/' -STATIC_ROOT = BASE_DIR / "staticfiles" + +if "DJANGO_STATIC_ROOT" in os.environ: + STATIC_ROOT = os.environ.get("DJANGO_STATIC_ROOT") +else: + STATIC_ROOT = BASE_DIR / "staticfiles" MEDIA_URL = 'media/' -MEDIA_ROOT = BASE_DIR / "mediafiles" + +if "DJANGO_MEDIA_ROOT" in os.environ: + MEDIA_ROOT = os.environ.get("DJANGO_MEDIA_ROOT") +else: + MEDIA_ROOT = BASE_DIR / "mediafiles" # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field From 7de5cd52d24846d606ef57f3fc4cc0ec7668ebb3 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 21:27:08 +0000 Subject: [PATCH 07/10] Fix up content --- .gitignore | 2 +- wedding_site/Dockerfile | 2 +- wedding_site/primary/static/primary/style.css | 5 +++-- wedding_site/primary/urls.py | 1 + wedding_site/primary/views.py | 6 +++++- wedding_site/wedding_site/settings.py | 6 ++++-- wedding_site/wedding_site/urls.py | 9 ++++++++- 7 files changed, 23 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 041559f..67588a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /build -*/uploads +*/mediafiles */staticfiles __pycache__ *.pyc diff --git a/wedding_site/Dockerfile b/wedding_site/Dockerfile index ded2fa5..0b84079 100644 --- a/wedding_site/Dockerfile +++ b/wedding_site/Dockerfile @@ -13,7 +13,7 @@ RUN pip install -r requirements.txt RUN mkdir staticfiles RUN mkdir mediafiles -ADD ./uploads /mediafiles +ADD ./mediafiles /mediafiles # copy project COPY . . \ No newline at end of file diff --git a/wedding_site/primary/static/primary/style.css b/wedding_site/primary/static/primary/style.css index bbd73c0..b1383e3 100755 --- a/wedding_site/primary/static/primary/style.css +++ b/wedding_site/primary/static/primary/style.css @@ -35,7 +35,8 @@ img { margin:0 auto; display: flex; justify-content: center; - max-width:800px; + max-width:100%; + max-height:300px; border-radius: 8px; box-shadow: 0 4px 8px 0; } @@ -146,7 +147,7 @@ input[type=submit] { margin-top: 30px; text-align: center; font-size: 20px; - width: 50%; + width: 75%; margin:0 auto; font-family: GlacialIndifference; } diff --git a/wedding_site/primary/urls.py b/wedding_site/primary/urls.py index bb59882..2fe363b 100644 --- a/wedding_site/primary/urls.py +++ b/wedding_site/primary/urls.py @@ -7,6 +7,7 @@ urlpatterns = [ path("", views.index, name="index"), path('login', views.login_view, name="login"), path("home", views.home, name="home"), + path("afters", views.afters, name="afters"), path("schedule", views.schedule, name="schedule"), path("thingstodo", views.things_to_do, name="thingstodo"), path("travel", views.travel, name="travel"), diff --git a/wedding_site/primary/views.py b/wedding_site/primary/views.py index b0d285b..969e793 100644 --- a/wedding_site/primary/views.py +++ b/wedding_site/primary/views.py @@ -27,7 +27,7 @@ _TEMPLATE = """ """ def handler404(request, exception, template_name="404.html"): - page_names = ["home", "schedule", "thingstodo"] + page_names = ["home", "schedule", "thingstodo", "afters"] working_path = request.path.lower() if working_path and working_path[0] == "/": working_path = working_path[1:] @@ -71,6 +71,10 @@ def login_view(request): def home(request): return get_page("Home") +@login_required(login_url="/") +def afters(request): + return get_page("Afters") + def get_page_header(site: Site): pages = site.page_set.order_by("priority").filter(navigable=True) diff --git a/wedding_site/wedding_site/settings.py b/wedding_site/wedding_site/settings.py index b7e5b95..b9b91cd 100644 --- a/wedding_site/wedding_site/settings.py +++ b/wedding_site/wedding_site/settings.py @@ -22,8 +22,10 @@ BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = os.environ.get("SECRET_KEY") -#DEBUG = bool(os.environ.get("DEBUG", default=0)) -#DEBUG=True +if "DJANGO_DEBUG" in os.environ: + DEBUG = os.environ.get("DJANGO_DEBUG") == 1 +else: + DEBUG=False if "DJANGO_ALLOWED_HOSTS" in os.environ: ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") diff --git a/wedding_site/wedding_site/urls.py b/wedding_site/wedding_site/urls.py index 539927f..0b74776 100644 --- a/wedding_site/wedding_site/urls.py +++ b/wedding_site/wedding_site/urls.py @@ -19,9 +19,16 @@ from django.urls import path, include from django.conf import settings from django.conf.urls.static import static +import os + +if "DJANGO_ADMIN_PATH" in os.environ: + ADMIN_URL = os.environ.get("DJANGO_ADMIN_PATH") + "/" +else: + ADMIN_URL = "admin/" + urlpatterns = [ path("", include('primary.urls')), - path('admin/', admin.site.urls), + path(ADMIN_URL, admin.site.urls), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) handler404 = 'primary.views.handler404' From c4ed1e079217b716da7892651605e44d0a98ee1f Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Sun, 18 Feb 2024 22:11:28 +0000 Subject: [PATCH 08/10] Fix password check --- wedding_site/primary/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wedding_site/primary/views.py b/wedding_site/primary/views.py index 969e793..01b4765 100644 --- a/wedding_site/primary/views.py +++ b/wedding_site/primary/views.py @@ -60,7 +60,7 @@ def index(request): def login_view(request): token = request.POST["token"] - user = authenticate(request, username="guest", password=token) + user = authenticate(request, username="guest", password=token.lower()) if user is not None: login(request, user) return redirect("home") From 06f53e830497732aaf843cfbb7b5f1707937bb79 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Thu, 22 Feb 2024 19:00:27 +0000 Subject: [PATCH 09/10] VIew view --- wedding_site/primary/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wedding_site/primary/views.py b/wedding_site/primary/views.py index 01b4765..30ffb5d 100644 --- a/wedding_site/primary/views.py +++ b/wedding_site/primary/views.py @@ -59,7 +59,10 @@ def index(request): return HttpResponse(soup.prettify()) def login_view(request): - token = request.POST["token"] + if request.method == "GET": + token = request.GET["token"] + else: + token = request.POST["token"] user = authenticate(request, username="guest", password=token.lower()) if user is not None: login(request, user) From 8ed93ebc12c35cd884749a22ffbc11b80fd42fe0 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Mon, 8 Apr 2024 08:56:33 +0100 Subject: [PATCH 10/10] Add some details on cert renewal. --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 8ead6d7..cc8fb86 100644 --- a/README.md +++ b/README.md @@ -42,5 +42,17 @@ Sync static files: podman-compose -f compose.prod.yaml exec web python manage.py collectstatic --no-input --clear ``` +Check cert + +```sh +podman-compose -f compose.prod.yaml exec acme-companion /app/cert_status +``` + +Force renew cert: + +```sh +podman-compose -f compose.prod.yaml exec acme-companion /app/force_renew +``` +