diff --git a/.circleci/config.yml b/.circleci/config.yml index 56e65ab7..a7bb7064 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -137,6 +137,7 @@ jobs: command: | pip install --upgrade uv"==0.8.*" --quiet --no-input - run: uv sync --only-group deploy --no-python-downloads + - setup_remote_docker - run: printenv DC_DEPLOY_NAME DJANGO_SETTINGS_MODULE SAM_CONFIG_FILE DC_ENVIRONMENT SAM_PUBLIC_CONFIG_ENV - run: printenv SECRET_KEY | md5sum - run: printenv AWS_ACCESS_KEY_ID | md5sum diff --git a/electionleaflets/apps/core/migrations/0002_delete_country_delete_emailalert_delete_emailque_and_more.py b/electionleaflets/apps/core/migrations/0002_delete_country_delete_emailalert_delete_emailque_and_more.py new file mode 100644 index 00000000..04ede095 --- /dev/null +++ b/electionleaflets/apps/core/migrations/0002_delete_country_delete_emailalert_delete_emailque_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.25 on 2025-10-15 15:01 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0001_initial"), + ] + + operations = [ + migrations.DeleteModel( + name="Country", + ), + migrations.DeleteModel( + name="EmailAlert", + ), + migrations.DeleteModel( + name="EmailQue", + ), + migrations.DeleteModel( + name="ImageQue", + ), + migrations.DeleteModel( + name="ImageQueSeq", + ), + ] diff --git a/electionleaflets/apps/leaflets/mixins.py b/electionleaflets/apps/leaflets/mixins.py new file mode 100644 index 00000000..35868068 --- /dev/null +++ b/electionleaflets/apps/leaflets/mixins.py @@ -0,0 +1,12 @@ +from django.contrib.auth.mixins import AccessMixin + + +class StaffuserRequiredMixin(AccessMixin): + """Require that the user is a staff member.""" + + permission_denied_message = "You must be a staff user to access this page." + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_staff: + return self.handle_no_permission() + return super().dispatch(request, *args, **kwargs) diff --git a/electionleaflets/apps/leaflets/tests/test_models.py b/electionleaflets/apps/leaflets/tests/test_models.py index 04aab68d..08b7d792 100644 --- a/electionleaflets/apps/leaflets/tests/test_models.py +++ b/electionleaflets/apps/leaflets/tests/test_models.py @@ -1,9 +1,17 @@ +from copy import deepcopy from pathlib import Path import pytest +from django.conf import settings +from django.test import override_settings from leaflets.models import Leaflet, LeafletImage from leaflets.tests.conftest import TEST_IMAGE_LOCATION +TEST_STORAGES = deepcopy(settings.STORAGES) +TEST_STORAGES["default"]["BACKEND"] = ( + "electionleaflets.storages.TempUploadS3MediaStorage" +) + @pytest.fixture def leaflet(): @@ -95,12 +103,8 @@ def test_image_moved_from_temp_upload(db, uploaded_temp_file): assert str(path) == leaflet_image.image.path -def test_image_moved_from_temp_upload_s3_backend( - db, settings, s3_bucket, s3_client -): - settings.DEFAULT_FILE_STORAGE = ( - "electionleaflets.storages.TempUploadS3MediaStorage" - ) +@override_settings(STORAGES=TEST_STORAGES) +def test_image_moved_from_temp_upload_s3_backend(db, s3_bucket, s3_client): leaflet = Leaflet() leaflet.save() leaflet.refresh_from_db() diff --git a/electionleaflets/apps/leaflets/views.py b/electionleaflets/apps/leaflets/views.py index 90781596..285cff7d 100644 --- a/electionleaflets/apps/leaflets/views.py +++ b/electionleaflets/apps/leaflets/views.py @@ -2,10 +2,10 @@ import json import random -from braces.views import LoginRequiredMixin, StaffuserRequiredMixin from core.helpers import CacheControlMixin from django.conf import settings from django.contrib import messages +from django.contrib.auth.mixins import LoginRequiredMixin from django.core.signing import Signer from django.db import transaction from django.db.models import Q @@ -24,6 +24,7 @@ SingleLeafletImageForm, UpdatePublisherDetails, ) +from .mixins import StaffuserRequiredMixin from .models import Leaflet, LeafletImage diff --git a/electionleaflets/settings/base.py b/electionleaflets/settings/base.py index ccfb4d42..95c7eaf5 100644 --- a/electionleaflets/settings/base.py +++ b/electionleaflets/settings/base.py @@ -6,6 +6,8 @@ from os.path import abspath, dirname, join import dc_design_system +from dc_utils.settings.pipeline import * # noqa +from dc_utils.settings.pipeline import get_pipeline_settings def here(x): @@ -51,7 +53,10 @@ def root(x): STATIC_URL = "/static/" STATICFILES_DIRS = (root("assets"),) -DEFAULT_FILE_STORAGE = "electionleaflets.storages.TempUploadLocalMediaStorage" +STORAGES["default"] = { # noqa F405 + "BACKEND": "electionleaflets.storages.TempUploadLocalMediaStorage" +} + AWS_S3_FILE_OVERWRITE = False STATICFILES_MANIFEST_NAME = environ.get( "STATICFILES_MANIFEST_NAME", "staticfiles.json" @@ -61,61 +66,33 @@ def root(x): # AWS_S3_HOST = "s3-eu-west-1.amazonaws.com" # AWS_S3_CUSTOM_DOMAIN = "data.electionleaflets.org" -PIPELINE = { - "COMPILERS": ("pipeline.compilers.sass.SASSCompiler",), - "SASS_BINARY": "pysassc", - "CSS_COMPRESSOR": "pipeline.compressors.NoopCompressor", - "STYLESHEETS": { - "styles": { - "source_filenames": [ - "scss/styles.scss", - "scss/vendor/filepond.css", - "scss/vendor/filepond-plugin-image-preview.css", - ], - "output_filename": "scss/styles.css", - "extra_context": { - "media": "screen,projection", - }, - }, - }, - "JAVASCRIPT": { - "scripts": { - "source_filenames": [ - "javascript/app.js", - "javascript/vendor/filepond.js", - "javascript/vendor/filepond-plugin-image-exif-orientation.js", - "javascript/vendor/filepond-plugin-image-preview.js", - "javascript/image_uploader.js", - # "javascript/vendor/ImageEditor.js", - ], - "output_filename": "app.js", - } - }, -} - +PIPELINE = get_pipeline_settings( + extra_css=[ + "scss/styles.scss", + "scss/vendor/filepond.css", + "scss/vendor/filepond-plugin-image-preview.css", + ], + extra_js=[ + "javascript/app.js", + "javascript/vendor/filepond.js", + "javascript/vendor/filepond-plugin-image-exif-orientation.js", + "javascript/vendor/filepond-plugin-image-preview.js", + "javascript/image_uploader.js", + # "javascript/vendor/ImageEditor.js", + ], +) -PIPELINE["CSS_COMPRESSOR"] = "pipeline.compressors.NoopCompressor" PIPELINE["JS_COMPRESSOR"] = "pipeline.compressors.NoopCompressor" - PIPELINE["SASS_ARGUMENTS"] = ( " -I " + dc_design_system.DC_SYSTEM_PATH + "/system" ) -STATICFILES_FINDERS = ( - "django.contrib.staticfiles.finders.FileSystemFinder", - "django.contrib.staticfiles.finders.AppDirectoriesFinder", - "pipeline.finders.CachedFileFinder", - "pipeline.finders.PipelineFinder", - "pipeline.finders.ManifestFinder", -) - WHITENOISE_STATIC_PREFIX = "/static/" SITE_ID = 1 SITE_LOGO = "images/logo.png" USE_I18N = False -USE_L10N = True LOGIN_URL = "/" # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a @@ -173,7 +150,6 @@ def root(x): "s3file", "django_filters", "dc_utils", - "querystring_tag", ] + LEAFLET_APPS diff --git a/electionleaflets/settings/base_lambda.py b/electionleaflets/settings/base_lambda.py index b81714da..07575cc5 100644 --- a/electionleaflets/settings/base_lambda.py +++ b/electionleaflets/settings/base_lambda.py @@ -30,7 +30,7 @@ WHITENOISE_STATIC_PREFIX = "/static/" STATIC_URL = WHITENOISE_STATIC_PREFIX -STATICFILES_STORAGE = "electionleaflets.storages.StaticStorage" +STORAGES["staticfiles"] = {"BACKEND": "electionleaflets.storages.StaticStorage"} # noqa F405 STATICFILES_DIRS = (root("assets"),) # noqa: F405 STATIC_ROOT = root("static") # noqa: F405 MEDIA_ROOT = root( # noqa: F405 @@ -41,7 +41,9 @@ AWS_DEFAULT_ACL = "public-read" -DEFAULT_FILE_STORAGE = "electionleaflets.storages.TempUploadS3MediaStorage" +STORAGES["default"] = { # noqa F405 + "BACKEND": "electionleaflets.storages.TempUploadS3MediaStorage" +} AWS_STORAGE_BUCKET_NAME = os.environ.get("LEAFLET_IMAGES_BUCKET_NAME") AWS_S3_SECURE_URLS = True diff --git a/electionleaflets/settings/local.py.example b/electionleaflets/settings/local.py.example index 2d5a846b..5908b070 100644 --- a/electionleaflets/settings/local.py.example +++ b/electionleaflets/settings/local.py.example @@ -14,8 +14,11 @@ DATABASES = { } } -DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' -STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' +STORAGES = { + "default": { "BACKEND": "django.core.files.storage.FileSystemStorage"}, + "staticfiles": { "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"}, +} + CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', @@ -25,3 +28,8 @@ CACHES = { #THUMBNAIL_DEBUG = True THUMBNAIL_KVSTORE ='sorl.thumbnail.kvstores.cached_db_kvstore.KVStore' + +# Debug Toolbar Setup +if DEBUG: + INSTALLED_APPS += ("debug_toolbar",) + MIDDLEWARE = ("debug_toolbar.middleware.DebugToolbarMiddleware",) + MIDDLEWARE # noqa: F405 \ No newline at end of file diff --git a/electionleaflets/settings/testing.py b/electionleaflets/settings/testing.py index 55d2c136..49c9b56e 100644 --- a/electionleaflets/settings/testing.py +++ b/electionleaflets/settings/testing.py @@ -5,8 +5,12 @@ os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" -DEFAULT_FILE_STORAGE = "electionleaflets.storages.TempUploadLocalMediaStorage" -STATICFILES_STORAGE = "electionleaflets.storages.StaticStorage" +STORAGES = { + "default": { + "BACKEND": "electionleaflets.storages.TempUploadLocalMediaStorage" + }, + "staticfiles": {"BACKEND": "electionleaflets.storages.StaticStorage"}, +} # This is cleaned up in core/conftest.py MEDIA_ROOT = mkdtemp() diff --git a/electionleaflets/templates/core/pager.html b/electionleaflets/templates/core/pager.html index d00c917c..b1e4cd2c 100644 --- a/electionleaflets/templates/core/pager.html +++ b/electionleaflets/templates/core/pager.html @@ -1,4 +1,3 @@ -{% load querystring_tag %} {% if page_obj.paginator.num_pages > 1 %}