""" Smooth Schedule Core App Admin Configuration """ from django.contrib import admin from django.utils.html import format_html from django.urls import reverse from django_tenants.admin import TenantAdminMixin from .models import Tenant, Domain, PermissionGrant @admin.register(Tenant) class TenantAdmin(TenantAdminMixin, admin.ModelAdmin): """ Admin interface for Tenant management. """ list_display = [ 'name', 'schema_name', 'subscription_tier', 'is_active', 'created_on', 'user_count', 'domain_list', ] list_filter = [ 'is_active', 'subscription_tier', 'created_on', ] search_fields = [ 'name', 'schema_name', 'contact_email', ] readonly_fields = [ 'schema_name', 'created_on', ] fieldsets = ( ('Basic Information', { 'fields': ('name', 'schema_name', 'created_on') }), ('Subscription', { 'fields': ('subscription_tier', 'is_active', 'max_users', 'max_resources') }), ('Contact', { 'fields': ('contact_email', 'phone') }), ) def user_count(self, obj): """Display count of users in this tenant""" count = obj.users.count() return format_html( '{}', 'green' if count < obj.max_users else 'red', count ) user_count.short_description = 'Users' def domain_list(self, obj): """Display list of domains for this tenant""" domains = obj.domain_set.all() if not domains: return '-' domain_links = [] for domain in domains: url = reverse('admin:core_domain_change', args=[domain.pk]) domain_links.append(f'{domain.domain}') return format_html(' | '.join(domain_links)) domain_list.short_description = 'Domains' @admin.register(Domain) class DomainAdmin(admin.ModelAdmin): """ Admin interface for Domain management. """ list_display = [ 'domain', 'tenant', 'is_primary', 'is_custom_domain', 'verified_status', ] list_filter = [ 'is_primary', 'is_custom_domain', ] search_fields = [ 'domain', 'tenant__name', ] readonly_fields = [ 'verified_at', ] fieldsets = ( ('Domain Information', { 'fields': ('domain', 'tenant', 'is_primary') }), ('Custom Domain Settings', { 'fields': ( 'is_custom_domain', 'route53_zone_id', 'route53_record_set_id', 'ssl_certificate_arn', 'verified_at', ), 'classes': ('collapse',), }), ) def verified_status(self, obj): """Display verification status with color coding""" if obj.is_verified(): return format_html( '✓ Verified' ) else: return format_html( '⚠ Pending' ) verified_status.short_description = 'Status' @admin.register(PermissionGrant) class PermissionGrantAdmin(admin.ModelAdmin): """ Admin interface for Permission Grant management. """ list_display = [ 'id', 'grantor', 'grantee', 'action', 'granted_at', 'expires_at', 'status', 'time_left', ] list_filter = [ 'action', 'granted_at', 'expires_at', ] search_fields = [ 'grantor__email', 'grantee__email', 'action', 'reason', ] readonly_fields = [ 'granted_at', 'grantor', 'grantee', 'ip_address', 'user_agent', ] fieldsets = ( ('Grant Information', { 'fields': ('grantor', 'grantee', 'action', 'reason') }), ('Timing', { 'fields': ('granted_at', 'expires_at', 'revoked_at') }), ('Audit Trail', { 'fields': ('ip_address', 'user_agent'), 'classes': ('collapse',), }), ) def status(self, obj): """Display status with color coding""" if obj.revoked_at: return format_html( '✗ Revoked' ) elif obj.is_active(): return format_html( '✓ Active' ) else: return format_html( '⊘ Expired' ) status.short_description = 'Status' def time_left(self, obj): """Display remaining time""" remaining = obj.time_remaining() if remaining is None: return '-' minutes = int(remaining.total_seconds() / 60) if minutes < 5: color = 'red' elif minutes < 15: color = 'orange' else: color = 'green' return format_html( '{} min', color, minutes ) time_left.short_description = 'Time Left' actions = ['revoke_grants'] def revoke_grants(self, request, queryset): """Admin action to revoke permission grants""" count = 0 for grant in queryset: if grant.is_active(): grant.revoke() count += 1 self.message_user( request, f'Successfully revoked {count} permission grant(s).' ) revoke_grants.short_description = 'Revoke selected grants'