from django.contrib import admin from django.utils import timezone from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ from unfold.admin import ModelAdmin, StackedInline from unfold.decorators import display, action from apps.account.models.verification import VerificationDocument from utils.admin import project_admin_site class VerificationDocumentInline(StackedInline): model = VerificationDocument fk_name = 'user' extra = 0 fields = ('document_type', 'title', 'document_file', 'document_preview', 'status', 'admin_notes', 'reviewed_by', 'uploaded_at') readonly_fields = ('uploaded_at', 'document_preview') @display(description=_('Preview / Download')) def document_preview(self, obj): if not obj or not obj.document_file: return _("No file uploaded") file_url = obj.document_file.url ext = obj.document_file.name.lower().split('.')[-1] if obj.document_file.name else '' if ext in ['jpg', 'jpeg', 'png', 'webp', 'gif']: return format_html( '' '' '
↗ Open Full File', url=file_url ) return format_html( '' '↗ Open / Download Document' '', url=file_url ) @admin.register(VerificationDocument, site=project_admin_site) class VerificationDocumentAdmin(ModelAdmin): list_display = ( 'id', 'user_display', 'document_type', 'title', 'document_link', 'status_badge', 'uploaded_at', 'reviewed_by', 'reviewed_at' ) list_display_links = ('id', 'user_display', 'document_type', 'title') list_filter = ('status', 'document_type', 'uploaded_at') search_fields = ('user__email', 'user__fullname', 'title', 'admin_notes') readonly_fields = ('uploaded_at', 'reviewed_at', 'document_preview') autocomplete_fields = ('user', 'reviewed_by') actions = ['approve_documents', 'reject_documents'] fieldsets = ( (_('Document Information'), { 'fields': ('user', 'document_type', 'title', 'document_file', 'document_preview') }), (_('Review Status'), { 'fields': ('status', 'admin_notes', 'reviewed_by', 'reviewed_at', 'uploaded_at') }), ) @display(description=_('User')) def user_display(self, obj): return obj.user.fullname or obj.user.email @display(description=_('File')) def document_link(self, obj): if not obj.document_file: return "-" return format_html( '' 'View File ↗' '', url=obj.document_file.url ) @display(description=_('Document Preview / File')) def document_preview(self, obj): if not obj or not obj.document_file: return _("No file uploaded") file_url = obj.document_file.url ext = obj.document_file.name.lower().split('.')[-1] if obj.document_file.name else '' if ext in ['jpg', 'jpeg', 'png', 'webp', 'gif']: return format_html( '
' '' '' '' '' '↗ Open Full Image in New Tab' '' '
', url=file_url ) elif ext == 'pdf': return format_html( '
' '' '' '↗ Open PDF in New Tab' '' '
', url=file_url ) else: return format_html( '' '📄 Open / Download File ({name}) ↗' '', url=file_url, name=obj.document_file.name.split('/')[-1] ) @display(description=_('Status'), label={ VerificationDocument.Status.VERIFIED: "success", VerificationDocument.Status.PENDING: "warning", VerificationDocument.Status.REJECTED: "danger", }) def status_badge(self, obj): return obj.get_status_display() def save_model(self, request, obj, form, change): if obj.status in [VerificationDocument.Status.VERIFIED, VerificationDocument.Status.REJECTED]: if not obj.reviewed_by: obj.reviewed_by = request.user if not obj.reviewed_at: obj.reviewed_at = timezone.now() super().save_model(request, obj, form, change) @action(description=_('Approve selected verification documents')) def approve_documents(self, request, queryset): queryset.update( status=VerificationDocument.Status.VERIFIED, reviewed_by=request.user, reviewed_at=timezone.now() ) self.message_user(request, _("Selected documents have been approved.")) @action(description=_('Reject selected verification documents')) def reject_documents(self, request, queryset): queryset.update( status=VerificationDocument.Status.REJECTED, reviewed_by=request.user, reviewed_at=timezone.now() ) self.message_user(request, _("Selected documents have been rejected."))