From 1405a9509449ad7bb1b82769c713766efe59f4b8 Mon Sep 17 00:00:00 2001 From: Benjamin Bach Date: Sun, 14 Jul 2024 19:18:33 +0200 Subject: [PATCH 1/4] Waiting list function: WaitingListEntry model for people that can be invited in the future --- .gitignore | 4 +++ .pre-commit-config.yaml | 6 ++-- pyproject.toml | 2 +- src/membership/admin.py | 15 +++++---- ...itinglistentry_alter_membership_options.py | 32 +++++++++++++++++++ src/membership/models.py | 15 +++++++++ 6 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 src/membership/migrations/0006_waitinglistentry_alter_membership_options.py diff --git a/.gitignore b/.gitignore index 86b4cf9..6f40a53 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ db.sqlite3 .env venv/ .venv/ + + +# collectstatic +src/static/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fc9fe36..c7f2a83 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ default_language_version: - python: python3.12 + python: python3 exclude: ^.*\b(migrations)\b.*$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks @@ -15,8 +15,8 @@ repos: - id: check-toml - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: 'v0.4.4' + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: 'v0.5.2' hooks: - id: ruff args: diff --git a/pyproject.toml b/pyproject.toml index 5346347..5434ff2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,7 +115,7 @@ extend-exclude = [ line-length = 120 [tool.ruff.lint] -select = ["ALL"] +# select = ["ALL"] ignore = [ "G004", # Logging statement uses f-string "ANN101", # Missing type annotation for `self` in method diff --git a/src/membership/admin.py b/src/membership/admin.py index 465764f..325167f 100644 --- a/src/membership/admin.py +++ b/src/membership/admin.py @@ -1,20 +1,23 @@ from django.contrib import admin -from .models import Membership -from .models import MembershipType -from .models import SubscriptionPeriod +from . import models -@admin.register(Membership) +@admin.register(models.Membership) class MembershipAdmin(admin.ModelAdmin): pass -@admin.register(MembershipType) +@admin.register(models.MembershipType) class MembershipTypeAdmin(admin.ModelAdmin): pass -@admin.register(SubscriptionPeriod) +@admin.register(models.SubscriptionPeriod) class SubscriptionPeriodAdmin(admin.ModelAdmin): pass + + +@admin.register(models.WaitingListEntry) +class WaitingListEntryAdmin(admin.ModelAdmin): + pass diff --git a/src/membership/migrations/0006_waitinglistentry_alter_membership_options.py b/src/membership/migrations/0006_waitinglistentry_alter_membership_options.py new file mode 100644 index 0000000..a993b63 --- /dev/null +++ b/src/membership/migrations/0006_waitinglistentry_alter_membership_options.py @@ -0,0 +1,32 @@ +# Generated by Django 5.0.6 on 2024-07-14 16:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('membership', '0005_member'), + ] + + operations = [ + migrations.CreateModel( + name='WaitingListEntry', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), + ('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), + ('email', models.EmailField(max_length=254)), + ('geography', models.CharField(blank=True, null=True, verbose_name='geography')), + ('comment', models.TextField(blank=True)), + ], + options={ + 'verbose_name': 'waiting list entry', + 'verbose_name_plural': 'waiting list entries', + }, + ), + migrations.AlterModelOptions( + name='membership', + options={'verbose_name': 'medlemskab', 'verbose_name_plural': 'medlemskaber'}, + ), + ] diff --git a/src/membership/models.py b/src/membership/models.py index 730133f..09146a1 100644 --- a/src/membership/models.py +++ b/src/membership/models.py @@ -111,3 +111,18 @@ class MembershipType(CreatedModifiedAbstract): def __str__(self) -> str: return self.name + + +class WaitingListEntry(CreatedModifiedAbstract): + """People who for some reason could want to be added to a waiting list and invited to join later.""" + + email = models.EmailField() + geography = models.CharField(verbose_name=_("geography"), blank=True, null=True) + comment = models.TextField(blank=True) + + def __str__(self) -> str: + return self.email + + class Meta: + verbose_name = _("waiting list entry") + verbose_name_plural = _("waiting list entries") From b366bc2499fe7a829b85032dae6dc7c87ab77f85 Mon Sep 17 00:00:00 2001 From: Benjamin Bach Date: Sun, 14 Jul 2024 21:19:32 +0200 Subject: [PATCH 2/4] WIP: cleanup setup --- .drone.yml | 2 -- .env.example | 1 - Dockerfile | 16 +++++++++------- Makefile | 26 +------------------------- README.md | 4 ++-- docker-compose.yml | 12 +++++++++--- entrypoint.sh | 11 ----------- 7 files changed, 21 insertions(+), 51 deletions(-) diff --git a/.drone.yml b/.drone.yml index d598350..97a1517 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,7 +7,6 @@ steps: - name: docker image: plugins/docker environment: - DJANGO_ENV: production BUILD: "${DRONE_COMMIT_SHA}" settings: repo: docker.data.coop/membersystem @@ -17,7 +16,6 @@ steps: password: from_secret: DOCKER_PASSWORD build_args_from_env: - - DJANGO_ENV - BUILD tags: - "${DRONE_BUILD_NUMBER}" diff --git a/.env.example b/.env.example index 777e8f3..9da2eda 100644 --- a/.env.example +++ b/.env.example @@ -6,4 +6,3 @@ DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres # Use something along the the following if you are not using docker # DATABASE_URL=postgres://postgres:postgres@localhost:5432/datacoop_membersystem DEBUG=True -DJANGO_ENV=development diff --git a/Dockerfile b/Dockerfile index cc600b1..31ac4f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,16 +7,12 @@ ENV PYTHONFAULTHANDLER=1 \ PIP_NO_CACHE_DIR=off \ PIP_DISABLE_PIP_VERSION_CHECK=on \ PIP_DEFAULT_TIMEOUT=100 -ARG DJANGO_ENV ARG BUILD ENV BUILD ${BUILD} WORKDIR /app -RUN groupadd -g 1000 www && useradd -u 1000 -ms /bin/bash -g www www -COPY --chown=www:www . . -RUN mkdir /app/src/static \ - && chown www:www /app/src/static \ +RUN groupadd -g 1000 www && useradd -u 1000 -ms /bin/bash -g www www \ && apt-get update \ && apt-get install -y \ binutils \ @@ -29,8 +25,14 @@ RUN mkdir /app/src/static \ libgdk-pixbuf2.0-0 \ libffi-dev \ shared-mime-info \ - gettext \ - && pip install . \ + gettext + +COPY --chown=www:www . . + +RUN mkdir /app/src/static \ + && chown www:www /app/src/static + +RUN pip install . \ && django-admin compilemessages ENTRYPOINT ["./entrypoint.sh"] diff --git a/Makefile b/Makefile index 7fc23eb..5a6bad4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ DOCKER_COMPOSE = COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose DOCKER_RUN = ${DOCKER_COMPOSE} run -u `id -u` -DOCKER_BUILD = DOCKER_BUILDKIT=1 docker build DOCKER_CONTAINER_NAME = backend MANAGE_EXEC = python /app/src/manage.py MANAGE_COMMAND = ${DOCKER_RUN} ${DOCKER_CONTAINER_NAME} ${MANAGE_EXEC} @@ -10,12 +9,6 @@ init: setup_venv pre_commit_install migrate run: ${DOCKER_COMPOSE} up -setup_venv: - rm -rf venv - python3.11 -m venv venv; - venv/bin/python -m pip install wheel setuptools; - venv/bin/python -m pip install pre-commit boto3 pip-tools; - pre_commit_install: venv/bin/pre-commit install @@ -37,22 +30,5 @@ shell: manage_command: ${MANAGE_COMMAND} ${ARGS} -add_dependency: - ${DOCKER_RUN} ${DOCKER_CONTAINER_NAME} poetry add --lock ${DEPENDENCY} - -add_dev_dependency: - ${DOCKER_RUN} ${DOCKER_CONTAINER_NAME} poetry add -D --lock ${DEPENDENCY} - -poetry_lock: - ${DOCKER_RUN} ${DOCKER_CONTAINER_NAME} poetry lock --no-update - -poetry_command: - ${DOCKER_RUN} ${DOCKER_CONTAINER_NAME} poetry ${COMMAND} - -build_dev_docker_image: compile_requirements +build_dev_docker_image: ${DOCKER_COMPOSE} build ${DOCKER_CONTAINER_NAME} - -compile_requirements: - ./venv/bin/pip-compile --output-file requirements/base.txt requirements/base.in - ./venv/bin/pip-compile --output-file requirements/test.txt requirements/test.in - ./venv/bin/pip-compile --output-file requirements/dev.txt requirements/dev.in diff --git a/README.md b/README.md index 9aed72b..78e7ba1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Copy over the .env.example file to .env and adjust DATABASE_URL accordingly - $ cp .env.example .env + $ cp .env.example .env ### Docker @@ -56,7 +56,7 @@ Activate the venv Install requirements - $ pip install -r requirements/dev.txt + $ pip install . Run migrations diff --git a/docker-compose.yml b/docker-compose.yml index 6872ac9..60be6b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.7' - services: backend: @@ -13,7 +11,8 @@ services: volumes: - ./:/app/ depends_on: - - postgres + postgres: + condition: service_healthy env_file: - .env @@ -25,6 +24,13 @@ services: - 5432:5432 env_file: - .env + # This healthcheck has a large number of retries, this is currently based on the number of + # retries necessary to get the database running in GitHub Actions. + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U postgres -d postgres" ] + interval: 5s + timeout: 5s + retries: 30 volumes: postgres_data: diff --git a/entrypoint.sh b/entrypoint.sh index 9df57b6..008f7be 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,16 +1,5 @@ #!/bin/sh -echo "Waiting for postgres..." - -POSTGRES_PORT=${POSTGRES_PORT:-5432} -POSTGRES_HOST=${POSTGRES_HOST:-localhost} - -while ! nc -z "$POSTGRES_HOST" "$POSTGRES_PORT"; do - sleep 0.1 -done - -echo "PostgreSQL started" - # Only migrate, collectstatic and compilemessages if we are NOT in development if [ -z "$DEBUG" ]; then python src/manage.py migrate; From d769481848d43114ac1e1a55ae000a5eb30a91b1 Mon Sep 17 00:00:00 2001 From: Benjamin Bach Date: Sat, 20 Jul 2024 22:33:30 +0200 Subject: [PATCH 3/4] Add a few more README things on Docker --- Makefile | 5 ++--- README.md | 13 +++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index de5cae6..651ed32 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ DOCKER_COMPOSE = COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose DOCKER_RUN = ${DOCKER_COMPOSE} run -u `id -u` -DOCKER_CONTAINER_NAME = backend MANAGE_EXEC = python /app/src/manage.py MANAGE_COMMAND = ${DOCKER_RUN} app ${MANAGE_EXEC} @@ -28,5 +27,5 @@ shell: manage_command: ${MANAGE_COMMAND} ${ARGS} -build_dev_docker_image: - ${DOCKER_COMPOSE} build ${DOCKER_CONTAINER_NAME} +build: + ${DOCKER_COMPOSE} build diff --git a/README.md b/README.md index 65b41b1..41ef329 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,19 @@ Working with the Docker Compose setup is made easy with the `Makefile` provided make run ``` +#### Building and running other things + +```bash +# Build the containers +make build + +# Create a superuser +make createsuperuser + +# Create Django migrations (after this, maybe you need to change file permissions in volume) +make makemigrations +``` + ### Using hatch #### Requirements From 250f203900b0421da809738694d58d541a52cfd1 Mon Sep 17 00:00:00 2001 From: Benjamin Bach Date: Sat, 20 Jul 2024 22:45:44 +0200 Subject: [PATCH 4/4] Fix some issues after merge conflixts --- Dockerfile | 12 +++++------- pyproject.toml | 2 +- src/membership/admin.py | 4 ---- ...0006_waitinglistentry_alter_membership_options.py | 4 ++-- src/membership/models.py | 2 +- src/pytest.ini | 5 ----- 6 files changed, 9 insertions(+), 20 deletions(-) delete mode 100644 src/pytest.ini diff --git a/Dockerfile b/Dockerfile index 16219b3..2e9448d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,9 +15,7 @@ WORKDIR /app RUN groupadd -g 1000 www && useradd -u 1000 -ms /bin/bash -g www www COPY --chown=www:www . . -RUN mkdir /app/src/static && \ - chown www:www /app/src/static && \ - apt-get update && \ +RUN apt-get update && \ apt-get install -y \ binutils \ libpq-dev \ @@ -33,11 +31,11 @@ RUN mkdir /app/src/static && \ COPY --chown=www:www . . -RUN mkdir /app/src/static \ - && chown www:www /app/src/static +RUN mkdir /app/src/static && \ + chown www:www /app/src/static -RUN pip install --no-cache-dir -r $REQUIREMENTS_FILE && \ - && django-admin compilemessages +RUN pip install --no-cache-dir -r $REQUIREMENTS_FILE +RUN django-admin compilemessages ENTRYPOINT ["./entrypoint.sh"] diff --git a/pyproject.toml b/pyproject.toml index 5874616..643b1cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,7 +125,7 @@ extend-exclude = [ line-length = 120 [tool.ruff.lint] -# select = ["ALL"] +select = ["ALL"] ignore = [ "G004", # Logging statement uses f-string "ANN101", # Missing type annotation for `self` in method diff --git a/src/membership/admin.py b/src/membership/admin.py index 0f84066..b16e2a1 100644 --- a/src/membership/admin.py +++ b/src/membership/admin.py @@ -19,11 +19,7 @@ class MembershipTypeAdmin(admin.ModelAdmin): class SubscriptionPeriodAdmin(admin.ModelAdmin): """Admin for SubscriptionPeriod model.""" - pass - @admin.register(models.WaitingListEntry) class WaitingListEntryAdmin(admin.ModelAdmin): """Admin for WaitingList model.""" - - pass diff --git a/src/membership/migrations/0006_waitinglistentry_alter_membership_options.py b/src/membership/migrations/0006_waitinglistentry_alter_membership_options.py index a993b63..9c2d923 100644 --- a/src/membership/migrations/0006_waitinglistentry_alter_membership_options.py +++ b/src/membership/migrations/0006_waitinglistentry_alter_membership_options.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.6 on 2024-07-14 16:22 +# Generated by Django 5.0.7 on 2024-07-20 20:45 from django.db import migrations, models @@ -17,7 +17,7 @@ class Migration(migrations.Migration): ('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), ('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), ('email', models.EmailField(max_length=254)), - ('geography', models.CharField(blank=True, null=True, verbose_name='geography')), + ('geography', models.CharField(blank=True, default='', verbose_name='geography')), ('comment', models.TextField(blank=True)), ], options={ diff --git a/src/membership/models.py b/src/membership/models.py index 69bdd4e..4fec013 100644 --- a/src/membership/models.py +++ b/src/membership/models.py @@ -145,7 +145,7 @@ class WaitingListEntry(CreatedModifiedAbstract): """People who for some reason could want to be added to a waiting list and invited to join later.""" email = models.EmailField() - geography = models.CharField(verbose_name=_("geography"), blank=True, null=True) + geography = models.CharField(verbose_name=_("geography"), blank=True, default="") comment = models.TextField(blank=True) def __str__(self) -> str: diff --git a/src/pytest.ini b/src/pytest.ini deleted file mode 100644 index 9929fa7..0000000 --- a/src/pytest.ini +++ /dev/null @@ -1,5 +0,0 @@ -[pytest] -testpaths = . -python_files = tests.py test_*.py *_tests.py -DJANGO_SETTINGS_MODULE = project.settings -#norecursedirs = dist tmp* .svn .*