# Source code for django_otp.plugins.otp_totp.admin

    from django.contrib import admin
    from django.contrib.admin.sites import AlreadyRegistered
    from django.core.exceptions import PermissionDenied
    from django.http import HttpResponse
    from django.template.response import TemplateResponse
    from django.urls import path, reverse
    from django.utils.html import format_html

    from django_otp.conf import settings

    from .models import TOTPDevice

    class TOTPDeviceAdmin(admin.ModelAdmin):
        """
        :class:`~django.contrib.admin.ModelAdmin` for
        :class:`~django_otp.plugins.otp_totp.models.TOTPDevice`.
        """
        list_display = ['user', 'name', 'confirmed']

        raw_id_fields = ['user']
        readonly_fields = ['qrcode_link']
        radio_fields = {'digits': admin.HORIZONTAL}

        def get_list_display(self, request):
            list_display = super().get_list_display(request)
            if not settings.OTP_ADMIN_HIDE_SENSITIVE_DATA:
                list_display = [*list_display, 'qrcode_link']
            return list_display

        def get_fieldsets(self, request, obj=None):
            # Show the key value only for adding new objects or when sensitive data
            # is not hidden.
            if settings.OTP_ADMIN_HIDE_SENSITIVE_DATA and obj:
                configuration_fields = ['step', 't0', 'digits', 'tolerance']
            else:
                configuration_fields = ['key', 'step', 't0', 'digits', 'tolerance']
            fieldsets = [
                ('Identity', {
                    'fields': ['user', 'name', 'confirmed'],
                }),
                ('Configuration', {
                    'fields': configuration_fields,
                }),
                ('State', {
                    'fields': ['drift'],
                }),
                ('Throttling', {
                    'fields': ['throttling_failure_timestamp', 'throttling_failure_count'],
                }),
            ]
            # Show the QR code link only for existing objects when sensitive data
            # is not hidden.
            if not settings.OTP_ADMIN_HIDE_SENSITIVE_DATA and obj:
                fieldsets.append(
                    (None, {
                        'fields': ['qrcode_link'],
                    }),
                )
            return fieldsets

        def get_queryset(self, request):
            queryset = super().get_queryset(request)
            queryset = queryset.select_related('user')

            return queryset

        #
        # Columns
        #

        def qrcode_link(self, device):
            try:
                href = reverse('admin:otp_totp_totpdevice_config', kwargs={'pk': device.pk})
                link = format_html('<a href="{}">qrcode</a>', href)
            except Exception:
                link = ''

            return link
        qrcode_link.short_description = "QR Code"

        #
        # Custom views
        #

        def get_urls(self):
            urls = [
                path('<int:pk>/config/', self.admin_site.admin_view(self.config_view), name='otp_totp_totpdevice_config'),
                path('<int:pk>/qrcode/', self.admin_site.admin_view(self.qrcode_view), name='otp_totp_totpdevice_qrcode'),
            ] + super().get_urls()

            return urls

        def config_view(self, request, pk):
            if settings.OTP_ADMIN_HIDE_SENSITIVE_DATA:
                raise PermissionDenied()

            device = TOTPDevice.objects.get(pk=pk)
            if not self.has_view_or_change_permission(request, device):
                raise PermissionDenied()

            context = dict(
                self.admin_site.each_context(request),
                device=device,
            )

            return TemplateResponse(request, 'otp_totp/admin/config.html', context)

        def qrcode_view(self, request, pk):
            if settings.OTP_ADMIN_HIDE_SENSITIVE_DATA:
                raise PermissionDenied()

            device = TOTPDevice.objects.get(pk=pk)
            if not self.has_view_or_change_permission(request, device):
                raise PermissionDenied()

            try:
                import qrcode
                import qrcode.image.svg

                img = qrcode.make(device.config_url, image_factory=qrcode.image.svg.SvgImage)
                response = HttpResponse(content_type='image/svg+xml')
                img.save(response)
            except ImportError:
                response = HttpResponse('', status=503)

            return response

    try:
        admin.site.register(TOTPDevice, TOTPDeviceAdmin)
    except AlreadyRegistered:
        # A useless exception from a double import
        pass