Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent exposing Django Admin features referencing media tables in prod #4349

Merged
merged 1 commit into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions api/api/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf import settings
from django.contrib import admin
from django.contrib.auth.admin import GroupAdmin, UserAdmin
from django.contrib.auth.models import Group, User
Expand Down Expand Up @@ -55,8 +56,9 @@
admin.site.register(klass, MediaSubreportAdmin)

# Temporary addition of model admin for decisions while this view gets built
admin.site.register(ImageDecision, admin.ModelAdmin)
admin.site.register(AudioDecision, admin.ModelAdmin)
if settings.ENVIRONMENT != "production":
admin.site.register(ImageDecision, admin.ModelAdmin)
admin.site.register(AudioDecision, admin.ModelAdmin)


@admin.register(ContentProvider)
Expand Down
23 changes: 19 additions & 4 deletions api/api/admin/media_report.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Sequence

from django.conf import settings
from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
Expand All @@ -17,6 +19,20 @@
logger = structlog.get_logger(__name__)


def _production_deferred(*values: str) -> Sequence[str]:
"""
Define a sequence in all environment except production.

The autocomplete/search queries in Django are woefully unoptimized for massive
tables, and so enabling certain utility features in production will often incur
a significant performance hit or outage. This will return the input values except
when the environment is production, in which case it will return an empty sequence.
"""
if settings.ENVIRONMENT == "production":
return ()
return values


class PredeterminedOrderChangelist(ChangeList):
"""
ChangeList class which does not apply any default ordering to the items.
Expand Down Expand Up @@ -65,8 +81,7 @@ class MediaListAdmin(admin.ModelAdmin):
list_filter = (PendingRecordCountFilter,)
# Disable link display for images
list_display_links = None
# Allow autocomplete to work from other referenced fields
search_fields = ("identifier",)
search_fields = _production_deferred("identifier")
media_type = None
# Ordering is not set here, see get_queryset

Expand Down Expand Up @@ -128,8 +143,8 @@ class MediaReportAdmin(admin.ModelAdmin):
)
list_display_links = ("id",)
list_select_related = ("media_obj",)
search_fields = ("description", "media_obj__identifier")
autocomplete_fields = ("media_obj",)
search_fields = _production_deferred("description", "media_obj__identifier")
autocomplete_fields = _production_deferred("media_obj")
actions = None
media_type = None

Expand Down
21 changes: 21 additions & 0 deletions api/test/unit/admin/test_media_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from unittest import mock

import pytest

from api.admin.media_report import _production_deferred


@pytest.mark.parametrize(
"values, environment, expected",
[
([1, 2, 3], "local", (1, 2, 3)),
([1, 2, 3], "production", ()),
([], "local", ()),
([], "production", ()),
],
)
def test_production_deferred(values, environment, expected):
with mock.patch("api.admin.media_report.settings") as mock_settings:
mock_settings.ENVIRONMENT = environment
actual = _production_deferred(*values)
assert actual == expected
Loading