From c23c52c9ab8e828002196d62386f0848e1065209 Mon Sep 17 00:00:00 2001 From: Marco Acierno Date: Sat, 7 Nov 2026 03:36:10 +0100 Subject: [PATCH 1/2] Fix warnings emitted by the backend test run - Restore export columns dropped by the django-import-export 4 upgrade: v4 ignores declared fields missing from Meta.fields, so the grant export lost email, age group and submission columns, and the ranking export lost the submission title. - Bump pytest-cov to 7.1.0; 4.x passes --rsyncdir to xdist, which is deprecated. - Use sentry_sdk.new_scope() and Scope.set_user() instead of the deprecated push_scope() and Scope.user setter. - Use pypdf's remove_duplicates/remove_unreferenced kwargs. - Drop WhiteNoise middleware in test settings: collectstatic does not run in CI, so it warns about the missing STATIC_ROOT. - Install libharfbuzz-subset0 in CI, matching the production image, so WeasyPrint stops warning about it. - Bump actions/setup-python to v7.1.0 (Node 24). --- .github/workflows/backend-checks.yml | 2 +- .github/workflows/backend-test.yml | 4 +++- .github/workflows/claude.yml | 2 +- .github/workflows/graphql-schema.yml | 2 +- backend/grants/admin.py | 8 ++++++++ backend/grants/tests/test_admin.py | 18 ++++++++++++++++++ backend/pretix/__init__.py | 4 ++-- backend/pycon/settings/test.py | 3 +++ backend/pyproject.toml | 2 +- backend/uv.lock | 11 ++++++----- backend/visa/tasks.py | 2 +- backend/voting/admin.py | 1 + backend/voting/tests/test_admin.py | 16 ++++++++++++++++ 13 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 backend/voting/tests/test_admin.py diff --git a/.github/workflows/backend-checks.yml b/.github/workflows/backend-checks.yml index 969290ceec..2ddffe518e 100644 --- a/.github/workflows/backend-checks.yml +++ b/.github/workflows/backend-checks.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 with: python-version: "3.14.7" - name: Install uv diff --git a/.github/workflows/backend-test.yml b/.github/workflows/backend-test.yml index 55e7d33a53..fdf7988d82 100644 --- a/.github/workflows/backend-test.yml +++ b/.github/workflows/backend-test.yml @@ -36,7 +36,7 @@ jobs: steps: - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 with: python-version: "3.14.7" - name: Install uv @@ -46,6 +46,8 @@ jobs: version: "0.12.5" enable-cache: true - run: pip install codecov + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libharfbuzz-subset0 - name: Install python dependencies if: steps.setup-uv.outputs.cache-hit != 'true' diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 9303dbcb24..9eb29fabc1 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -68,7 +68,7 @@ jobs: uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 1 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 with: python-version: "3.14.7" - name: Install uv diff --git a/.github/workflows/graphql-schema.yml b/.github/workflows/graphql-schema.yml index 3183c56cac..6351d4495e 100644 --- a/.github/workflows/graphql-schema.yml +++ b/.github/workflows/graphql-schema.yml @@ -20,7 +20,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 with: python-version: "3.14.7" diff --git a/backend/grants/admin.py b/backend/grants/admin.py index 914f0390e2..939b15b07b 100644 --- a/backend/grants/admin.py +++ b/backend/grants/admin.py @@ -71,6 +71,14 @@ "departure_country", "conference__code", "created", + "age_group", + "email", + "has_sent_submission", + "submission_title", + "submission_tags", + "submission_admin_link", + "submission_pycon_link", + "grant_admin_link", ) diff --git a/backend/grants/tests/test_admin.py b/backend/grants/tests/test_admin.py index b51c8d93e1..5b5988229b 100644 --- a/backend/grants/tests/test_admin.py +++ b/backend/grants/tests/test_admin.py @@ -33,6 +33,8 @@ GrantReimbursementFactory, ) from grants.models import Grant, GrantReimbursement +from i18n.strings import LazyI18nString +from submissions.tests.factories import SubmissionFactory pytestmark = pytest.mark.django_db @@ -887,6 +889,22 @@ def test_export_includes_one_column_per_form_question(): assert rows[1]["First time?"] == "" +def test_export_includes_applicant_and_submission_columns(): + conference = ConferenceFactory() + grant = GrantFactory(conference=conference) + SubmissionFactory( + conference=conference, + speaker=grant.user, + title=LazyI18nString({"en": "My talk"}), + ) + + row = _export_grants(conference).dict[0] + + assert row["email"] == grant.user.email + assert row["has_sent_submission"] == "TRUE" + assert row["submission_title"] == "My talk" + + def test_export_without_a_form_has_no_extra_columns(): conference = ConferenceFactory() GrantFactory(conference=conference) diff --git a/backend/pretix/__init__.py b/backend/pretix/__init__.py index 49395208c2..305445d9de 100644 --- a/backend/pretix/__init__.py +++ b/backend/pretix/__init__.py @@ -568,8 +568,8 @@ def create_order(conference: Conference, order_data: CreateOrderInput) -> Order: ) if response.status_code != 200: - with sentry_sdk.push_scope() as scope: - scope.user = {"email": order_data.email} + with sentry_sdk.new_scope() as scope: + scope.set_user({"email": order_data.email}) scope.set_extra("order-code", data["code"]) scope.set_extra("pec", order_data.invoice_information.pec) scope.set_extra( diff --git a/backend/pycon/settings/test.py b/backend/pycon/settings/test.py index 98bf2e2663..829cf33db7 100644 --- a/backend/pycon/settings/test.py +++ b/backend/pycon/settings/test.py @@ -10,6 +10,9 @@ if "debug_toolbar.middleware.DebugToolbarMiddleware" in MIDDLEWARE: MIDDLEWARE.remove("debug_toolbar.middleware.DebugToolbarMiddleware") +# collectstatic never runs in tests, so STATIC_ROOT does not exist +MIDDLEWARE.remove("whitenoise.middleware.WhiteNoiseMiddleware") + SECRET_KEY = "this-key-should-only-be-used-for-tests" HASHID_DEFAULT_SECRET_SALT = "only-for-tests" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 9a75392554..c108a976c9 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -126,7 +126,7 @@ text = "MIT" dev = [ "mypy<2.0.0,>=1.2.0", "pytest==9.0.3", - "pytest-cov==4.1.0", + "pytest-cov==7.1.0", "pytest-django==4.6.0", "factory-boy==3.3.3", "pdbpp<1.0.0,>=0.10.3", diff --git a/backend/uv.lock b/backend/uv.lock index 23cb1308eb..5c2a60a879 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 5 +revision = 3 requires-python = ">=3.14.7" resolution-markers = [ "python_full_version >= '3.15' and sys_platform == 'win32'", @@ -450,7 +450,7 @@ dev = [ { name = "pdbpp", specifier = ">=0.10.3,<1.0.0" }, { name = "pytest", specifier = "==9.0.3" }, { name = "pytest-cache", specifier = ">=1.0,<2.0" }, - { name = "pytest-cov", specifier = "==4.1.0" }, + { name = "pytest-cov", specifier = "==7.1.0" }, { name = "pytest-django", specifier = "==4.6.0" }, { name = "pytest-mock", specifier = ">=3.12.0,<4.0.0" }, { name = "pytest-xdist", specifier = ">=3.5.0" }, @@ -3235,15 +3235,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/d1/15/082fd0428aab33d2b [[package]] name = "pytest-cov" -version = "4.1.0" +version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage" }, + { name = "pluggy" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/15/da3df99fd551507694a9b01f512a2f6cf1254f33601605843c3775f39460/pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", size = 63245, upload-time = "2023-05-24T18:44:56.845Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/4b/8b78d126e275efa2379b1c2e09dc52cf70df16fc3b90613ef82531499d73/pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a", size = 21949, upload-time = "2023-05-24T18:44:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, ] [[package]] diff --git a/backend/visa/tasks.py b/backend/visa/tasks.py index 5069ed5234..db298eeb96 100644 --- a/backend/visa/tasks.py +++ b/backend/visa/tasks.py @@ -87,7 +87,7 @@ def process_invitation_letter_request(*, invitation_letter_request_id: int): pretix_ticket = download_pretix_ticket(invitation_letter_request) merger.append(pretix_ticket) - merger.compress_identical_objects(remove_identicals=True, remove_orphans=True) + merger.compress_identical_objects(remove_duplicates=True, remove_unreferenced=True) with tempfile.NamedTemporaryFile() as invitation_letter_file: merger.write(invitation_letter_file) diff --git a/backend/voting/admin.py b/backend/voting/admin.py index a15fd6a759..6592517d89 100644 --- a/backend/voting/admin.py +++ b/backend/voting/admin.py @@ -82,6 +82,7 @@ class Media: "full_name", "gender", "rank_request__conference__code", + "submission__title", ) diff --git a/backend/voting/tests/test_admin.py b/backend/voting/tests/test_admin.py new file mode 100644 index 0000000000..e620baa175 --- /dev/null +++ b/backend/voting/tests/test_admin.py @@ -0,0 +1,16 @@ +import pytest + +from i18n.strings import LazyI18nString +from voting.admin import RankSubmissionResource +from voting.models import RankSubmission +from voting.tests.factories.ranking import RankSubmissionFactory + +pytestmark = pytest.mark.django_db + + +def test_rank_submission_export_includes_submission_title(): + RankSubmissionFactory(submission__title=LazyI18nString({"en": "My talk"})) + + dataset = RankSubmissionResource().export(queryset=RankSubmission.objects.all()) + + assert dataset.dict[0]["submission__title"] == "My talk" From ab275599fcc7902f8697213955ee4783c44a44ea Mon Sep 17 00:00:00 2001 From: Marco Acierno Date: Sat, 7 Nov 2026 15:24:17 +0100 Subject: [PATCH 2/2] Default admin URL fields to https Silences Django's RemovedInDjango60Warning about forms.URLField's assume_scheme by opting into the Django 6 default: a URL entered in the admin without a scheme ("example.com") is saved as "https://example.com" instead of "http://example.com". Admins and inlines with URL fields set formfield_overrides; module-level ModelForms set Meta.formfield_callback, since ModelAdmin replaces it with its own when it builds the form. A test builds every registered admin and inline form and checks that its URL fields assume https, so a new admin that misses the override fails. --- backend/badge_scanner/admin.py | 3 +++ backend/conferences/admin/conference.py | 2 ++ backend/custom_admin/admin.py | 11 +++++++++ backend/custom_admin/tests/test_admin.py | 31 ++++++++++++++++++++++++ backend/events/admin.py | 3 +++ backend/google_api/admin.py | 3 +++ backend/grants/admin.py | 3 +++ backend/participants/admin.py | 6 +++++ backend/schedule/admin.py | 10 +++++++- backend/sponsors/admin.py | 3 +++ backend/submissions/admin.py | 6 +++++ backend/video_uploads/admin.py | 6 +++++ 12 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 backend/custom_admin/tests/test_admin.py diff --git a/backend/badge_scanner/admin.py b/backend/badge_scanner/admin.py index 6e9a846668..b641eeddc0 100644 --- a/backend/badge_scanner/admin.py +++ b/backend/badge_scanner/admin.py @@ -1,11 +1,14 @@ from django.contrib import admin +from custom_admin.admin import HTTPS_URL_FORMFIELD_OVERRIDES + from .models import BadgeScan @admin.register(BadgeScan) class BadgeScanAdmin(admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES autocomplete_fields = ( "scanned_by", "scanned_user", diff --git a/backend/conferences/admin/conference.py b/backend/conferences/admin/conference.py index eebd8c48ee..5ee03fb24d 100644 --- a/backend/conferences/admin/conference.py +++ b/backend/conferences/admin/conference.py @@ -35,6 +35,7 @@ Topic, ) from conferences.admin.views import grants_summary +from custom_admin.admin import HTTPS_URL_FORMFIELD_OVERRIDES from .actions import ( clone_conference, create_conference_vouchers_on_pretix, @@ -110,6 +111,7 @@ class ConferenceAdmin( OrderedInlineModelAdminMixin, admin.ModelAdmin, ): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES list_display = ( "name", "code", diff --git a/backend/custom_admin/admin.py b/backend/custom_admin/admin.py index a832dc40ad..20daeb31d3 100644 --- a/backend/custom_admin/admin.py +++ b/backend/custom_admin/admin.py @@ -1,3 +1,4 @@ +from django.db import models from django.db.models import F from django.contrib import messages from functools import wraps @@ -13,6 +14,16 @@ admin.site.site_header = SITE_NAME admin.site.site_title = SITE_NAME +HTTPS_URL_FORMFIELD_OVERRIDES = {models.URLField: {"assume_scheme": "https"}} + + +def formfield_with_https_urls(db_field, **kwargs): + # ModelAdmin replaces a form's formfield_callback with its own, so admins + # also need HTTPS_URL_FORMFIELD_OVERRIDES + if isinstance(db_field, models.URLField): + kwargs.setdefault("assume_scheme", "https") + return db_field.formfield(**kwargs) + class CustomIndexLinks(admin.ModelAdmin): def get_index_links(self) -> list: diff --git a/backend/custom_admin/tests/test_admin.py b/backend/custom_admin/tests/test_admin.py new file mode 100644 index 0000000000..67d718efef --- /dev/null +++ b/backend/custom_admin/tests/test_admin.py @@ -0,0 +1,31 @@ +import pytest +from django import forms +from django.contrib import admin + +pytestmark = pytest.mark.django_db + + +def test_admin_url_fields_default_to_https(rf, admin_superuser): + request = rf.get("/") + request.user = admin_superuser + form_classes = {} + for model_admin in admin.site._registry.values(): + form_classes[type(model_admin).__name__] = model_admin.get_form( + request, fields=None + ) + for inline in model_admin.get_inline_instances(request): + form_classes[type(inline).__name__] = inline.get_formset( + request, fields=None + ).form + + cleaned_urls = { + f"{admin_name}.{field_name}": field.clean("example.com") + for admin_name, form_class in form_classes.items() + for field_name, field in form_class.base_fields.items() + if isinstance(field, forms.URLField) + } + + assert cleaned_urls + assert { + name: url for name, url in cleaned_urls.items() if url != "https://example.com" + } == {} diff --git a/backend/events/admin.py b/backend/events/admin.py index 49034fad06..2b18e9fcd0 100644 --- a/backend/events/admin.py +++ b/backend/events/admin.py @@ -1,10 +1,13 @@ from django.contrib import admin +from custom_admin.admin import HTTPS_URL_FORMFIELD_OVERRIDES + from .models import Event @admin.register(Event) class EventAdmin(admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES list_display = ("title", "start", "end", "conference") fieldsets = ( ( diff --git a/backend/google_api/admin.py b/backend/google_api/admin.py index 0e38359e1c..1f1299aa6a 100644 --- a/backend/google_api/admin.py +++ b/backend/google_api/admin.py @@ -6,6 +6,7 @@ from django.shortcuts import redirect from django.urls import path, reverse from import_export.admin import ImportExportModelAdmin +from custom_admin.admin import HTTPS_URL_FORMFIELD_OVERRIDES from google_api.models import GoogleCloudOAuthCredential, GoogleCloudToken import google_auth_oauthlib.flow from django.utils.safestring import mark_safe @@ -14,6 +15,7 @@ class GoogleCloudTokenInline(admin.StackedInline): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES model = GoogleCloudToken autocomplete_fields = ("admin_user",) extra = 0 @@ -24,6 +26,7 @@ def has_add_permission(self, request, obj=None): @admin.register(GoogleCloudOAuthCredential) class GoogleCloudOAuthCredentialAdmin(ImportExportModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES inlines = [GoogleCloudTokenInline] def get_list_display(self, request): diff --git a/backend/grants/admin.py b/backend/grants/admin.py index 939b15b07b..d340b3fb55 100644 --- a/backend/grants/admin.py +++ b/backend/grants/admin.py @@ -25,6 +25,7 @@ from countries import countries from countries.filters import CountryFilter from custom_admin.admin import ( + HTTPS_URL_FORMFIELD_OVERRIDES, confirm_pending_status, reset_pending_status_back_to_status, validate_single_conference_selection, @@ -518,6 +519,7 @@ def delete_model(self, request, obj): @admin.register(Grant) class GrantAdmin(ExportMixin, ConferencePermissionMixin, admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES change_list_template = "admin/grants/grant/change_list.html" resource_classes = [GrantResource] list_display = ( @@ -807,6 +809,7 @@ class Media: @admin.register(GrantConfirmPendingStatusProxy) class GrantConfirmPendingStatusProxyAdmin(admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES list_display = ( "id", "full_name", diff --git a/backend/participants/admin.py b/backend/participants/admin.py index beaafaea67..0ac75fad65 100644 --- a/backend/participants/admin.py +++ b/backend/participants/admin.py @@ -2,17 +2,23 @@ from django.contrib import admin from django.utils.safestring import mark_safe +from custom_admin.admin import ( + HTTPS_URL_FORMFIELD_OVERRIDES, + formfield_with_https_urls, +) from participants.models import Participant class ParticipantForm(forms.ModelForm): class Meta: model = Participant + formfield_callback = formfield_with_https_urls fields = "__all__" @admin.register(Participant) class ParticipantAdmin(admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES form = ParticipantForm search_fields = ("user__email", "user__full_name") list_display = ( diff --git a/backend/schedule/admin.py b/backend/schedule/admin.py index 380471a88e..8da7259a46 100644 --- a/backend/schedule/admin.py +++ b/backend/schedule/admin.py @@ -1,5 +1,9 @@ from django.db import transaction -from custom_admin.admin import validate_single_conference_selection +from custom_admin.admin import ( + HTTPS_URL_FORMFIELD_OVERRIDES, + formfield_with_https_urls, + validate_single_conference_selection, +) from import_export.resources import ModelResource from django.db.models import Count, Prefetch from typing import Dict @@ -281,6 +285,7 @@ def __init__(self, *args, **kwargs): class Meta: model = ScheduleItem + formfield_callback = formfield_with_https_urls fields = ( "conference", "type", @@ -308,6 +313,7 @@ class Meta: @admin.register(ScheduleItem) class ScheduleItemAdmin(ConferencePermissionMixin, admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES list_display = ( "title", "conference", @@ -618,6 +624,7 @@ class Meta: @admin.register(ScheduleItemInvitation) class ScheduleItemInvitationAdmin(ExportMixin, admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES resource_classes = [ScheduleItemInvitationResource] list_display = ( "slot", @@ -711,6 +718,7 @@ class RoomAdmin(OrderedModelAdmin): class DayRoomThroughModelInline(OrderedTabularInline): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES model = DayRoomThroughModel fields = ("room", "order", "move_up_down_links", "streaming_url", "slido_url") readonly_fields = ( diff --git a/backend/sponsors/admin.py b/backend/sponsors/admin.py index 6055c8e4b4..e6fe36f03a 100644 --- a/backend/sponsors/admin.py +++ b/backend/sponsors/admin.py @@ -1,6 +1,8 @@ from django.contrib import admin from ordered_model.admin import OrderedModelAdmin +from custom_admin.admin import HTTPS_URL_FORMFIELD_OVERRIDES + from .models import ( Sponsor, SponsorLead, @@ -13,6 +15,7 @@ @admin.register(Sponsor) class SponsorAdmin(OrderedModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES list_display = ("name", "move_up_down_links") list_filter = ( "levels__conference", diff --git a/backend/submissions/admin.py b/backend/submissions/admin.py index 093eb8e1ab..7b7e73ee13 100644 --- a/backend/submissions/admin.py +++ b/backend/submissions/admin.py @@ -2,7 +2,9 @@ from grants.tasks import get_name from notifications.models import EmailTemplate, EmailTemplateIdentifier from custom_admin.admin import ( + HTTPS_URL_FORMFIELD_OVERRIDES, confirm_pending_status, + formfield_with_https_urls, reset_pending_status_back_to_status, validate_single_conference_selection, ) @@ -139,6 +141,7 @@ class Meta: class SubmissionAdminForm(forms.ModelForm): class Meta: model = Submission + formfield_callback = formfield_with_https_urls fields = [ "title", "slug", @@ -208,6 +211,7 @@ def send_proposal_in_waiting_list_email_action(modeladmin, request, queryset): class ProposalMaterialInline(admin.TabularInline): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES model = ProposalMaterial extra = 0 autocomplete_fields = ("file",) @@ -215,6 +219,7 @@ class ProposalMaterialInline(admin.TabularInline): @admin.register(Submission) class SubmissionAdmin(ExportMixin, ConferencePermissionMixin, admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES resource_classes = [SubmissionResource] form = SubmissionAdminForm list_display = ( @@ -387,6 +392,7 @@ def apply_and_notify_status_change(modeladmin, request, queryset): @admin.register(SubmissionConfirmPendingStatusProxy) class SubmissionConfirmPendingStatusProxyAdmin(admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES list_display = ( "id", "title", diff --git a/backend/video_uploads/admin.py b/backend/video_uploads/admin.py index 4d1c2a8d7f..46b1490fb9 100644 --- a/backend/video_uploads/admin.py +++ b/backend/video_uploads/admin.py @@ -3,6 +3,10 @@ from django.contrib import admin from django.db import transaction +from custom_admin.admin import ( + HTTPS_URL_FORMFIELD_OVERRIDES, + formfield_with_https_urls, +) from pycon.tasks import check_pending_heavy_processing_work from video_uploads.tasks import process_videos_import_request from video_uploads.models import VideosImportRequest @@ -31,6 +35,7 @@ def retry_transfer(modeladmin, request, queryset): class VideosImportRequestAdminForm(forms.ModelForm): class Meta: model = VideosImportRequest + formfield_callback = formfield_with_https_urls fields = ["conference", "source_url"] def clean_source_url(self): @@ -46,6 +51,7 @@ def clean_source_url(self): @admin.register(VideosImportRequest) class VideosImportRequestAdmin(admin.ModelAdmin): + formfield_overrides = HTTPS_URL_FORMFIELD_OVERRIDES form = VideosImportRequestAdminForm list_display = [ "conference",