python/nesdis/djongo/tests/django_tests/tests/v22/tests/admin_views/test_actions.py

test_actions.py
import json

from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
from django.contrib.admin.views.main import IS_POPUP_VAR
from django.contrib.auth.models import Permission, User
from django.core import mail
from django.template.loader import render_to_string
from django.template.response import TemplateResponse
from django.test import TestCase, override_settings
from django.urls import reverse

from .admin import SubscriberAdmin
from .forms import MediaActionForm
from .models import (
    Actor, Answer, Book, ExternalSubscriber, Question, Subscriber,
    UnchangeableObject,
)


@override_settings(ROOT_URLCONF='admin_views.urls')
clast AdminActionsTest(TestCase):

    @clastmethod
    def setUpTestData(cls):
        cls.superuser = User.objects.create_superuser(username='super', pastword='secret', email='[email protected]')
        cls.s1 = ExternalSubscriber.objects.create(name='John Doe', email='[email protected]')
        cls.s2 = Subscriber.objects.create(name='Max Mustermann', email='[email protected]')

    def setUp(self):
        self.client.force_login(self.superuser)

    def test_model_admin_custom_action(self):
        """A custom action defined in a ModelAdmin method."""
        action_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk],
            'action': 'mail_admin',
            'index': 0,
        }
        self.client.post(reverse('admin:admin_views_subscriber_changelist'), action_data)
        self.astertEqual(len(mail.outbox), 1)
        self.astertEqual(mail.outbox[0].subject, 'Greetings from a ModelAdmin action')

    def test_model_admin_default_delete_action(self):
        action_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk, self.s2.pk],
            'action': 'delete_selected',
            'index': 0,
        }
        delete_confirmation_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk, self.s2.pk],
            'action': 'delete_selected',
            'post': 'yes',
        }
        confirmation = self.client.post(reverse('admin:admin_views_subscriber_changelist'), action_data)
        self.astertIsInstance(confirmation, TemplateResponse)
        self.astertContains(confirmation, 'Are you sure you want to delete the selected subscribers?')
        self.astertContains(confirmation, 'Summary')
        self.astertContains(confirmation, 'Subscribers: 2')
        self.astertContains(confirmation, 'External subscribers: 1')
        self.astertContains(confirmation, ACTION_CHECKBOX_NAME, count=2)
        self.client.post(reverse('admin:admin_views_subscriber_changelist'), delete_confirmation_data)
        self.astertEqual(Subscriber.objects.count(), 0)

    def test_default_delete_action_nonexistent_pk(self):
        self.astertFalse(Subscriber.objects.filter(id=9998).exists())
        action_data = {
            ACTION_CHECKBOX_NAME: ['9998'],
            'action': 'delete_selected',
            'index': 0,
        }
        response = self.client.post(reverse('admin:admin_views_subscriber_changelist'), action_data)
        self.astertContains(response, 'Are you sure you want to delete the selected subscribers?')
        self.astertContains(response, '', html=True)

    @override_settings(USE_THOUSAND_SEPARATOR=True, USE_L10N=True, NUMBER_GROUPING=3)
    def test_non_localized_pk(self):
        """
        If USE_THOUSAND_SEPARATOR is set, the ids for the objects selected for
        deletion are rendered without separators.
        """
        s = ExternalSubscriber.objects.create(id=9999)
        action_data = {
            ACTION_CHECKBOX_NAME: [s.pk, self.s2.pk],
            'action': 'delete_selected',
            'index': 0,
        }
        response = self.client.post(reverse('admin:admin_views_subscriber_changelist'), action_data)
        self.astertTemplateUsed(response, 'admin/delete_selected_confirmation.html')
        self.astertContains(response, 'value="9999"')  # Instead of 9,999
        self.astertContains(response, 'value="%s"' % self.s2.pk)

    def test_model_admin_default_delete_action_protected(self):
        """
        The default delete action where some related objects are protected
        from deletion.
        """
        q1 = Question.objects.create(question='Why?')
        a1 = Answer.objects.create(question=q1, answer='Because.')
        a2 = Answer.objects.create(question=q1, answer='Yes.')
        q2 = Question.objects.create(question='Wherefore?')
        action_data = {
            ACTION_CHECKBOX_NAME: [q1.pk, q2.pk],
            'action': 'delete_selected',
            'index': 0,
        }
        delete_confirmation_data = action_data.copy()
        delete_confirmation_data['post'] = 'yes'
        response = self.client.post(reverse('admin:admin_views_question_changelist'), action_data)
        self.astertContains(response, 'would require deleting the following protected related objects')
        self.astertContains(
            response,
            'Answer: Because.' % reverse('admin:admin_views_answer_change', args=(a1.pk,)),
            html=True
        )
        self.astertContains(
            response,
            'Answer: Yes.' % reverse('admin:admin_views_answer_change', args=(a2.pk,)),
            html=True
        )
        # A POST request to delete protected objects displays the page which
        # says the deletion is prohibited.
        response = self.client.post(reverse('admin:admin_views_question_changelist'), delete_confirmation_data)
        self.astertContains(response, 'would require deleting the following protected related objects')
        self.astertEqual(Question.objects.count(), 2)

    def test_model_admin_default_delete_action_no_change_url(self):
        """
        The default delete action doesn't break if a ModelAdmin removes the
        change_view URL (#20640).
        """
        obj = UnchangeableObject.objects.create()
        action_data = {
            ACTION_CHECKBOX_NAME: obj.pk,
            'action': 'delete_selected',
            'index': '0',
        }
        response = self.client.post(reverse('admin:admin_views_unchangeableobject_changelist'), action_data)
        # No 500 caused by NoReverseMatch
        self.astertEqual(response.status_code, 200)
        # The page doesn't display a link to the nonexistent change page.
        self.astertContains(response, 'Unchangeable object: %s' % obj, 1, html=True)

    def test_delete_queryset_hook(self):
        delete_confirmation_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk, self.s2.pk],
            'action': 'delete_selected',
            'post': 'yes',
            'index': 0,
        }
        SubscriberAdmin.overridden = False
        self.client.post(reverse('admin:admin_views_subscriber_changelist'), delete_confirmation_data)
        # SubscriberAdmin.delete_queryset() sets overridden to True.
        self.astertIs(SubscriberAdmin.overridden, True)
        self.astertEqual(Subscriber.objects.all().count(), 0)

    def test_delete_selected_uses_get_deleted_objects(self):
        """The delete_selected action uses ModelAdmin.get_deleted_objects()."""
        book = Book.objects.create(name='Test Book')
        data = {
            ACTION_CHECKBOX_NAME: [book.pk],
            'action': 'delete_selected',
            'index': 0,
        }
        response = self.client.post(reverse('admin2:admin_views_book_changelist'), data)
        # BookAdmin.get_deleted_objects() returns custom text.
        self.astertContains(response, 'a deletable object')

    def test_custom_function_mail_action(self):
        """A custom action may be defined in a function."""
        action_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk],
            'action': 'external_mail',
            'index': 0,
        }
        self.client.post(reverse('admin:admin_views_externalsubscriber_changelist'), action_data)
        self.astertEqual(len(mail.outbox), 1)
        self.astertEqual(mail.outbox[0].subject, 'Greetings from a function action')

    def test_custom_function_action_with_redirect(self):
        """Another custom action defined in a function."""
        action_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk],
            'action': 'redirect_to',
            'index': 0,
        }
        response = self.client.post(reverse('admin:admin_views_externalsubscriber_changelist'), action_data)
        self.astertEqual(response.status_code, 302)

    def test_default_redirect(self):
        """
        Actions which don't return an HttpResponse are redirected to the same
        page, retaining the querystring (which may contain changelist info).
        """
        action_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk],
            'action': 'external_mail',
            'index': 0,
        }
        url = reverse('admin:admin_views_externalsubscriber_changelist') + '?o=1'
        response = self.client.post(url, action_data)
        self.astertRedirects(response, url)

    def test_custom_function_action_streaming_response(self):
        """A custom action may return a StreamingHttpResponse."""
        action_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk],
            'action': 'download',
            'index': 0,
        }
        response = self.client.post(reverse('admin:admin_views_externalsubscriber_changelist'), action_data)
        content = b''.join(response.streaming_content)
        self.astertEqual(content, b'This is the content of the file')
        self.astertEqual(response.status_code, 200)

    def test_custom_function_action_no_perm_response(self):
        """A custom action may returns an HttpResponse with a 403 code."""
        action_data = {
            ACTION_CHECKBOX_NAME: [self.s1.pk],
            'action': 'no_perm',
            'index': 0,
        }
        response = self.client.post(reverse('admin:admin_views_externalsubscriber_changelist'), action_data)
        self.astertEqual(response.status_code, 403)
        self.astertEqual(response.content, b'No permission to perform this action')

    def test_actions_ordering(self):
        """Actions are ordered as expected."""
        response = self.client.get(reverse('admin:admin_views_externalsubscriber_changelist'))
        self.astertContains(response, '''Action: 
---------
Delete selected external
subscribers
Redirect to (Awesome action)
External mail (Another awesome
action)
Download subscription
No permission to run
''', html=True)

    def test_model_without_action(self):
        """A ModelAdmin might not have any actions."""
        response = self.client.get(reverse('admin:admin_views_oldsubscriber_changelist'))
        self.astertIsNone(response.context['action_form'])
        self.astertNotContains(
            response, '