From cdda8bae76473a4003d3a3f77176f6e729e36011 Mon Sep 17 00:00:00 2001 From: ldeluigi <44567586+ldeluigi@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:07:16 +0100 Subject: [PATCH] Add 'website' application for dynamic frontend fields --- backend/Dockerfile | 1 + backend/backend/production_settings.py | 1 + backend/backend/settings.py | 1 + backend/spellbook/urls.py | 4 ++- backend/spellbook/views.py | 3 +-- backend/website/__init__.py | 0 backend/website/admin.py | 13 +++++++++ backend/website/management/__init__.py | 0 .../website/management/commands/__init__.py | 0 .../commands/seed_website_properties.py | 23 ++++++++++++++++ backend/website/migrations/0001_initial.py | 27 +++++++++++++++++++ backend/website/migrations/__init__.py | 0 backend/website/models.py | 21 +++++++++++++++ backend/website/serializers.py | 8 ++++++ backend/website/tests.py | 0 backend/website/urls.py | 10 +++++++ backend/website/views.py | 8 ++++++ 17 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 backend/website/__init__.py create mode 100644 backend/website/admin.py create mode 100644 backend/website/management/__init__.py create mode 100644 backend/website/management/commands/__init__.py create mode 100644 backend/website/management/commands/seed_website_properties.py create mode 100644 backend/website/migrations/0001_initial.py create mode 100644 backend/website/migrations/__init__.py create mode 100644 backend/website/models.py create mode 100644 backend/website/serializers.py create mode 100644 backend/website/tests.py create mode 100644 backend/website/urls.py create mode 100644 backend/website/views.py diff --git a/backend/Dockerfile b/backend/Dockerfile index 383a88b0..ea07f056 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -71,6 +71,7 @@ sleep 3\n\ python manage.py migrate --noinput\n\ python manage.py clean_jobs\n\ python manage.py export_variants\n\ +python manage.py seed_website_properties\n\ gunicorn backend.wsgi:application --bind 0.0.0.0:8000\n' > entrypoint.prod.sh EXPOSE 8000 ENTRYPOINT ["/bin/sh", "entrypoint.prod.sh"] diff --git a/backend/backend/production_settings.py b/backend/backend/production_settings.py index 20853609..69d315c6 100644 --- a/backend/backend/production_settings.py +++ b/backend/backend/production_settings.py @@ -58,6 +58,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'spellbook', + 'website', 'django.contrib.admin', 'sortedm2m', 'rest_framework', diff --git a/backend/backend/settings.py b/backend/backend/settings.py index f177a644..bb782115 100644 --- a/backend/backend/settings.py +++ b/backend/backend/settings.py @@ -44,6 +44,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'spellbook', + 'website', 'django.contrib.admin', 'sortedm2m', 'rest_framework', diff --git a/backend/spellbook/urls.py b/backend/spellbook/urls.py index 65b2d01d..e3d955a7 100644 --- a/backend/spellbook/urls.py +++ b/backend/spellbook/urls.py @@ -1,6 +1,7 @@ from django.urls import include, path -from . import views from rest_framework.routers import DefaultRouter +from . import views +from website.urls import router as website_router router = DefaultRouter() router.register(r'variants', views.VariantViewSet, basename='variants') @@ -8,6 +9,7 @@ router.register(r'combos', views.ComboViewSet, basename='combos') router.register(r'cards', views.CardViewSet, basename='cards') router.register(r'templates', views.TemplateViewSet, basename='templates') +router.registry.extend(website_router.registry) urlpatterns = [ path('', include(router.urls)) diff --git a/backend/spellbook/views.py b/backend/spellbook/views.py index 5c09319a..2c0c825a 100644 --- a/backend/spellbook/views.py +++ b/backend/spellbook/views.py @@ -1,7 +1,6 @@ from .models import Card, Feature, Combo, Template, Variant from .serializers import CardDetailSerializer, FeatureSerializer, ComboDetailSerializer, TemplateSerializer, VariantSerializer -from rest_framework import viewsets -from rest_framework import filters +from rest_framework import viewsets, filters from django_filters.rest_framework import DjangoFilterBackend diff --git a/backend/website/__init__.py b/backend/website/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/website/admin.py b/backend/website/admin.py new file mode 100644 index 00000000..ff71da81 --- /dev/null +++ b/backend/website/admin.py @@ -0,0 +1,13 @@ +from django.contrib import admin +from .models import WebsiteProperty + + +@admin.register(WebsiteProperty) +class WebsitePropertyAdmin(admin.ModelAdmin): + list_display = ('key', 'value') + + def has_add_permission(self, request) -> bool: + return False + + def has_delete_permission(self, request, obj=None) -> bool: + return False diff --git a/backend/website/management/__init__.py b/backend/website/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/website/management/commands/__init__.py b/backend/website/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/website/management/commands/seed_website_properties.py b/backend/website/management/commands/seed_website_properties.py new file mode 100644 index 00000000..48831709 --- /dev/null +++ b/backend/website/management/commands/seed_website_properties.py @@ -0,0 +1,23 @@ +from django.core.management.base import BaseCommand +from website.models import WebsiteProperty, PROPERTY_KEYS + + +class Command(BaseCommand): + help = 'Seed website properties' + + def handle(self, *args, **options): + self.stdout.write('Seeding website properties...') + properties = set(PROPERTY_KEYS) + existing = set(WebsiteProperty.objects.values_list('key', flat=True)) + missing = properties - existing + obsolete = existing - properties + if missing: + self.stdout.write(f'Creating missing properties: {", ".join(missing)}') + WebsiteProperty.objects.bulk_create([ + WebsiteProperty(key=key) + for key in missing + ]) + if obsolete: + self.stdout.write(f'Deleting obsolete properties: {", ".join(obsolete)}') + WebsiteProperty.objects.filter(key__in=obsolete).delete() + self.stdout.write(self.style.SUCCESS('Website properties were seeded.')) diff --git a/backend/website/migrations/0001_initial.py b/backend/website/migrations/0001_initial.py new file mode 100644 index 00000000..089d0575 --- /dev/null +++ b/backend/website/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# Generated by Django 4.1.5 on 2023-03-02 15:25 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='WebsiteProperty', + fields=[ + ('key', models.CharField(editable=False, max_length=100, primary_key=True, serialize=False, unique=True)), + ('description', models.TextField(blank=True)), + ('value', models.CharField(blank=True, help_text='Comma-separated list of values', max_length=1000, validators=[django.core.validators.RegexValidator('^[^\\,]+(?:\\,[^\\,]+)*$')])), + ], + options={ + 'verbose_name': 'Website Property', + 'verbose_name_plural': 'Website Properties', + }, + ), + ] diff --git a/backend/website/migrations/__init__.py b/backend/website/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/website/models.py b/backend/website/models.py new file mode 100644 index 00000000..fd439cee --- /dev/null +++ b/backend/website/models.py @@ -0,0 +1,21 @@ +from django.db import models +from django.core.validators import RegexValidator + + +PROPERTY_KEYS = [ + 'featured_combos_title', + 'featured_set_codes', +] + + +class WebsiteProperty(models.Model): + key = models.CharField(max_length=100, unique=True, blank=False, primary_key=True, editable=False) + value = models.CharField(max_length=1000, blank=True, validators=[RegexValidator(r'^[^\,]+(?:\,[^\,]+)*$')], help_text='Comma-separated list of values') + description = models.TextField(blank=True) + + def __str__(self): + return self.key.replace("_", " ").title() + + class Meta: + verbose_name = 'Website Property' + verbose_name_plural = 'Website Properties' diff --git a/backend/website/serializers.py b/backend/website/serializers.py new file mode 100644 index 00000000..17e8a884 --- /dev/null +++ b/backend/website/serializers.py @@ -0,0 +1,8 @@ +from rest_framework import serializers +from .models import WebsiteProperty + + +class WebsitePropertySerializer(serializers.ModelSerializer): + class Meta: + model = WebsiteProperty + fields = ['key', 'description', 'value'] diff --git a/backend/website/tests.py b/backend/website/tests.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/website/urls.py b/backend/website/urls.py new file mode 100644 index 00000000..f757d192 --- /dev/null +++ b/backend/website/urls.py @@ -0,0 +1,10 @@ +from django.urls import include, path +from . import views +from rest_framework.routers import DefaultRouter + +router = DefaultRouter() +router.register(r'properties', views.WebsitePropertyViewSet, basename='properties') + +urlpatterns = [ + path('', include(router.urls)) +] diff --git a/backend/website/views.py b/backend/website/views.py new file mode 100644 index 00000000..c1e1b34b --- /dev/null +++ b/backend/website/views.py @@ -0,0 +1,8 @@ +from rest_framework import viewsets +from .models import WebsiteProperty +from .serializers import WebsitePropertySerializer + + +class WebsitePropertyViewSet(viewsets.ReadOnlyModelViewSet): + queryset = WebsiteProperty.objects.all() + serializer_class = WebsitePropertySerializer