Set up docker

- fix some post things
master
Pete Ley 6 months ago
parent 286d108964
commit e4ab79de42

@ -1,60 +1,22 @@
# Use an official Python runtime based on Debian 10 "buster" as a parent image.
FROM python:3.8.1-slim-buster
# Add user that will be used in the container.
FROM python:3.11.6-slim-bookworm
RUN useradd wagtail
# Port used by this container to serve HTTP.
EXPOSE 8000
# Set environment variables.
# 1. Force Python stdout and stderr streams to be unbuffered.
# 2. Set PORT variable that is used by Gunicorn. This should match "EXPOSE"
# command.
ENV PYTHONUNBUFFERED=1 \
PORT=8000
# Install system packages required by Wagtail and Django.
RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-recommends \
build-essential \
libpq-dev \
libmariadbclient-dev \
libmariadb-dev \
libjpeg62-turbo-dev \
zlib1g-dev \
libwebp-dev \
&& rm -rf /var/lib/apt/lists/*
# Install the application server.
RUN pip install "gunicorn==20.0.4"
# Install the project requirements.
RUN pip install gunicorn
COPY requirements.txt /
RUN pip install -r /requirements.txt
# Use /app folder as a directory where the source code is stored.
WORKDIR /app
# Set this directory to be owned by the "wagtail" user. This Wagtail project
# uses SQLite, the folder needs to be owned by the user that
# will be writing to the database file.
RUN chown wagtail:wagtail /app
# Copy the source code of the project into the container.
COPY --chown=wagtail:wagtail . .
# Use user "wagtail" to run the build commands below and the server itself.
USER wagtail
# Collect static files.
RUN python manage.py collectstatic --noinput --clear
# Runtime command that executes when "docker run" is called, it does the
# following:
# 1. Migrate the database.
# 2. Start the application server.
# WARNING:
# Migrating database at the same time as starting the server IS NOT THE BEST
# PRACTICE. The database should be migrated manually or using the release
# phase facilities of your hosting platform. This is used only so the
# Wagtail instance can be started with a simple "docker run" command.
CMD set -xe; python manage.py migrate --noinput; gunicorn triplethink.wsgi:application
CMD set -xe; gunicorn --reload triplethink.wsgi:application

@ -1,4 +1,4 @@
# Generated by Django 4.2.6 on 2023-10-26 19:13
# Generated by Django 4.2.6 on 2023-11-13 16:04
import blog.models
from django.db import migrations, models
@ -11,173 +11,101 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
("wagtailcore", "0089_log_entry_data_json_null_to_object"),
("wagtailimages", "0025_alter_image_file_alter_rendition_file"),
('wagtailimages', '0025_alter_image_file_alter_rendition_file'),
('wagtailcore', '0089_log_entry_data_json_null_to_object'),
]
operations = [
migrations.CreateModel(
name="ArticleIndexPage",
name='ArticlePage',
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('body', wagtail.fields.RichTextField()),
],
options={
"abstract": False,
'abstract': False,
},
bases=(blog.models.PostIndexMixin, "wagtailcore.page"),
bases=(blog.models.PostMixin, 'wagtailcore.page'),
),
migrations.CreateModel(
name="ArticlePage",
name='NotePage',
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
("body", wagtail.fields.RichTextField()),
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('body', wagtail.fields.RichTextField(max_length=500)),
],
options={
"abstract": False,
'abstract': False,
},
bases=(blog.models.PostMixin, "wagtailcore.page"),
bases=(blog.models.PostMixin, 'wagtailcore.page'),
),
migrations.CreateModel(
name="NoteIndexPage",
name='PostIndexPage',
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('blurb', models.TextField(blank=True, null=True)),
('posts_per_page', models.IntegerField(default=15)),
],
options={
"abstract": False,
'abstract': False,
},
bases=(blog.models.PostIndexMixin, "wagtailcore.page"),
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name="NotePage",
name='Tagline',
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
("body", wagtail.fields.RichTextField(max_length=500)),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.CharField(max_length=255)),
],
),
migrations.CreateModel(
name='ArticleIndexPage',
fields=[
('postindexpage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.postindexpage')),
],
options={
"abstract": False,
'abstract': False,
},
bases=(blog.models.PostMixin, "wagtailcore.page"),
bases=('blog.postindexpage',),
),
migrations.CreateModel(
name="PhotoIndexPage",
name='NoteIndexPage',
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
('postindexpage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.postindexpage')),
],
options={
"abstract": False,
'abstract': False,
},
bases=(blog.models.PostIndexMixin, "wagtailcore.page"),
bases=('blog.postindexpage',),
),
migrations.CreateModel(
name="RootIndexPage",
name='PhotoIndexPage',
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
('postindexpage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.postindexpage')),
],
options={
"abstract": False,
'abstract': False,
},
bases=(blog.models.PostIndexMixin, "wagtailcore.page"),
bases=('blog.postindexpage',),
),
migrations.CreateModel(
name="Tagline",
name='RootIndexPage',
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.CharField(max_length=255)),
('postindexpage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='blog.postindexpage')),
],
options={
'abstract': False,
},
bases=('blog.postindexpage',),
),
migrations.CreateModel(
name="PhotoPage",
name='PhotoPage',
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
(
"photo",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="wagtailimages.image",
),
),
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('photo', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='wagtailimages.image')),
],
options={
"abstract": False,
'abstract': False,
},
bases=(blog.models.PostMixin, "wagtailcore.page"),
bases=(blog.models.PostMixin, 'wagtailcore.page'),
),
]

@ -1,20 +0,0 @@
# Generated by Django 4.2.6 on 2023-11-01 20:18
from django.db import migrations
def delete_init_site(apps, _schema_editor):
Site = apps.get_model("wagtailcore.Site")
Site.objects.first().delete()
Page = apps.get_model("wagtailcore.Page")
Page.objects.filter(slug='home').first().delete()
class Migration(migrations.Migration):
dependencies = [
("blog", "0001_initial"),
('wagtailcore', '0002_initial_data'),
]
operations = [migrations.RunPython(delete_init_site)]

@ -74,11 +74,6 @@ PageQuerySet.authorized = authorized
class PostMixin:
subpage_types = []
def authorized(self, request):
if restrictions := self.get_view_restrictions():
return all([r.accept_request(request) for r in restrictions])
return True
def index_snippet(self):
return f'blog/_{self.content_type.model[:-4]}_index.html'
@ -126,9 +121,19 @@ class PhotoPage(PostMixin, Page):
parent_page_types = ['PhotoIndexPage']
class PostIndexMixin:
class PostIndexPage(Page):
show_in_menus_default = True
blurb = models.TextField(blank=True, null=True)
posts_per_page = models.IntegerField(default=15)
parent_page_types = ['blog.RootIndexPage']
content_panels = Page.content_panels + [
FieldPanel('blurb'),
FieldPanel('posts_per_page'),
]
def get_template(self, *args, **kwargs):
return 'blog/post_index_page.html'
@ -139,58 +144,42 @@ class PostIndexMixin:
.live() \
.filter(show_in_menus=False) \
.order_by('-first_published_at')
for ptype in ['note', 'article', 'photo']:
count = posts.filter(content_type__model=f'{ptype}page').count()
context[f'{ptype}_count'] = count
page = request.GET.get('p')
paginator = Paginator(posts, 15)
paginator = Paginator(posts, self.posts_per_page)
try:
posts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
posts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
posts = paginator.page(paginator.num_pages)
context['posts'] = posts
return context
class RootIndexPage(PostIndexMixin, Page):
class RootIndexPage(PostIndexPage):
subpage_types = [
'NoteIndexPage',
'ArticleIndexPage',
'PhotoIndexPage',
]
def get_template(self, *args, **kwargs):
return 'blog/root_index_page.html'
def get_context(self, request):
context = super().get_context(request)
context['note_count'] = NotePage.objects \
.live() \
.authorized(request) \
.count()
context['article_count'] = ArticlePage.objects \
.live() \
.authorized(request) \
.count()
context['photo_count'] = PhotoPage.objects \
.live() \
.authorized(request) \
.count()
return context
parent_page_types = [Page]
class NoteIndexPage(PostIndexMixin, Page):
class NoteIndexPage(PostIndexPage):
parent_page_types = ['RootIndexPage']
subpage_types = ['NotePage']
class ArticleIndexPage(PostIndexMixin, Page):
class ArticleIndexPage(PostIndexPage):
parent_page_types = ['RootIndexPage']
subpage_types = ['ArticlePage']
class PhotoIndexPage(PostIndexMixin, Page):
class PhotoIndexPage(PostIndexPage):
parent_page_types = ['RootIndexPage']
subpage_types = ['PhotoPage']

@ -37,7 +37,7 @@
<h1 class="my-2 my-lg-0 me-lg-auto">
<a class="blog-header-logo text-body-emphasis text-decoration-none" href="/">triplethink</a>
</h1>
<p class="ms-3 me-md-2 align-self-end">{{ tagline }}</p>
<p class="ms-3 me-md-2 align-self-end">{{ tagline|default_if_none:'' }}</p>
<ul class="nav col-12 col-lg-auto my-2 justify-content-center my-md-0 text-small overflow-x-auto">
{% with svg_class="d-block mx-auto mb-1 bi" %}
<li>

@ -59,5 +59,21 @@
{% endblock content %}
{% block sidebar %}
Index metadata
<div class="column">
<p class="fs-4">{{ page.specific.blurb }}</p>
<div class="list-group list-group-flush">
{% if note_count > 0 %}
<a class="list-group-item list-group-item-action"
href="/notes/">{{note_count}} Note{{ note_count|pluralize }}</a>
{% endif %}
{% if article_count > 0 %}
<a class="list-group-item list-group-item-action"
href="/articles/">{{article_count}} Article{{ article_count|pluralize }}</a>
{% endif %}
{% if photo_count > 0 %}
<a class="list-group-item list-group-item-action"
href="/articles/">{{photo_count}} Photo{{ photo_count|pluralize }}</a>
{% endif %}
</div>
</div>
{% endblock %}

@ -1,18 +0,0 @@
{% extends 'blog/post_index_page.html' %}
{% block sidebar %}
<div class="column">
<div class="h-card">
<p class="fs-4">
Hello. My name is <span class="p-name">Pete</span>. Sometimes
I post things here.
</p>
</div>
<div class="list-group list-group-flush">
<a class="list-group-item list-group-item-action"
href="/notes/">{{note_count}} Notes</a>
<a class="list-group-item list-group-item-action"
href="/articles/">{{article_count}} Articles</a>
</div>
</div>
{% endblock %}

@ -0,0 +1,14 @@
services:
web:
build: .
ports:
- "8000:8000"
volumes:
- .:/app
depends_on:
- db
db:
image: "postgres"
restart: always
environment:
POSTGRES_PASSWORD: postpass

@ -24,6 +24,7 @@ markdown-headdown==0.1.3
openpyxl==3.1.2
Pillow==10.1.0
pillow-heif==0.13.1
psycopg==3.1.12
pytz==2023.3.post1
requests==2.31.0
six==1.16.0

@ -87,8 +87,12 @@ WSGI_APPLICATION = "triplethink.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
"ENGINE": "django.db.backends.postgresql",
'NAME': 'postgres',
'USER': 'postgres',
'PASSWORD': 'postpass',
'HOST': 'db',
'PORT': 5432,
}
}

Loading…
Cancel
Save