""" System Module Admin """ from django.contrib import admin from unfold.admin import ModelAdmin from igny8_core.admin.base import AccountAdminMixin, Igny8ModelAdmin from .models import AIPrompt, IntegrationSettings, AuthorProfile, Strategy from django.contrib import messages from import_export.admin import ExportMixin, ImportExportMixin from import_export import resources class AIPromptResource(resources.ModelResource): """Resource class for importing/exporting AI Prompts""" class Meta: model = AIPrompt fields = ('id', 'account__name', 'prompt_type', 'prompt_value', 'is_active', 'created_at') export_order = fields import_id_fields = ('id',) skip_unchanged = True # Import settings admin from .settings_admin import ( SystemSettingsAdmin, AccountSettingsAdmin, UserSettingsAdmin, ModuleSettingsAdmin, AISettingsAdmin ) try: from .models import SystemLog, SystemStatus @admin.register(SystemLog) class SystemLogAdmin(AccountAdminMixin, Igny8ModelAdmin): list_display = ['id', 'account', 'module', 'level', 'action', 'message', 'created_at'] list_filter = ['module', 'level', 'created_at', 'account'] search_fields = ['message', 'action'] readonly_fields = ['created_at', 'updated_at'] date_hierarchy = 'created_at' @admin.register(SystemStatus) class SystemStatusAdmin(AccountAdminMixin, Igny8ModelAdmin): list_display = ['component', 'account', 'status', 'message', 'last_check'] list_filter = ['status', 'component', 'account'] search_fields = ['component', 'message'] readonly_fields = ['last_check'] except ImportError: pass @admin.register(AIPrompt) class AIPromptAdmin(ImportExportMixin, AccountAdminMixin, Igny8ModelAdmin): resource_class = AIPromptResource list_display = ['id', 'prompt_type', 'account', 'is_active', 'updated_at'] list_filter = ['prompt_type', 'is_active', 'account'] search_fields = ['prompt_type'] readonly_fields = ['created_at', 'updated_at', 'default_prompt'] actions = [ 'bulk_activate', 'bulk_deactivate', 'bulk_reset_to_default', ] fieldsets = ( ('Basic Info', { 'fields': ('account', 'prompt_type', 'is_active') }), ('Prompt Content', { 'fields': ('prompt_value', 'default_prompt') }), ('Timestamps', { 'fields': ('created_at', 'updated_at') }), ) def get_account_display(self, obj): """Safely get account name""" try: account = getattr(obj, 'account', None) return account.name if account else '-' except: return '-' get_account_display.short_description = 'Account' def bulk_activate(self, request, queryset): updated = queryset.update(is_active=True) self.message_user(request, f'{updated} AI prompt(s) activated.', messages.SUCCESS) bulk_activate.short_description = 'Activate selected prompts' def bulk_deactivate(self, request, queryset): updated = queryset.update(is_active=False) self.message_user(request, f'{updated} AI prompt(s) deactivated.', messages.SUCCESS) bulk_deactivate.short_description = 'Deactivate selected prompts' def bulk_reset_to_default(self, request, queryset): count = 0 for prompt in queryset: if prompt.default_prompt: prompt.prompt_value = prompt.default_prompt prompt.save() count += 1 self.message_user(request, f'{count} AI prompt(s) reset to default values.', messages.SUCCESS) bulk_reset_to_default.short_description = 'Reset to default values' class IntegrationSettingsResource(resources.ModelResource): """Resource class for exporting Integration Settings (config masked)""" class Meta: model = IntegrationSettings fields = ('id', 'account__name', 'integration_type', 'is_active', 'created_at') export_order = fields @admin.register(IntegrationSettings) class IntegrationSettingsAdmin(ExportMixin, AccountAdminMixin, Igny8ModelAdmin): resource_class = IntegrationSettingsResource list_display = ['id', 'integration_type', 'account', 'is_active', 'updated_at'] list_filter = ['integration_type', 'is_active', 'account'] search_fields = ['integration_type'] readonly_fields = ['created_at', 'updated_at'] actions = [ 'bulk_activate', 'bulk_deactivate', 'bulk_test_connection', ] fieldsets = ( ('Basic Info', { 'fields': ('account', 'integration_type', 'is_active') }), ('Configuration', { 'fields': ('config',), 'description': 'JSON configuration containing API keys and settings. Example: {"apiKey": "sk-...", "model": "gpt-4.1", "enabled": true}' }), ('Timestamps', { 'fields': ('created_at', 'updated_at') }), ) def get_readonly_fields(self, request, obj=None): """Make config readonly when viewing to prevent accidental exposure""" if obj: # Editing existing object return self.readonly_fields + ['config'] return self.readonly_fields def get_account_display(self, obj): """Safely get account name""" try: account = getattr(obj, 'account', None) return account.name if account else '-' except: return '-' get_account_display.short_description = 'Account' def bulk_activate(self, request, queryset): updated = queryset.update(is_active=True) self.message_user(request, f'{updated} integration setting(s) activated.', messages.SUCCESS) bulk_activate.short_description = 'Activate selected integrations' def bulk_deactivate(self, request, queryset): updated = queryset.update(is_active=False) self.message_user(request, f'{updated} integration setting(s) deactivated.', messages.SUCCESS) bulk_deactivate.short_description = 'Deactivate selected integrations' def bulk_test_connection(self, request, queryset): """Test connection for selected integration settings""" count = queryset.filter(is_active=True).count() self.message_user( request, f'{count} integration(s) queued for connection test. (Test logic to be implemented)', messages.INFO ) bulk_test_connection.short_description = 'Test connections' class AuthorProfileResource(resources.ModelResource): """Resource class for importing/exporting Author Profiles""" class Meta: model = AuthorProfile fields = ('id', 'name', 'account__name', 'tone', 'language', 'is_active', 'created_at') export_order = fields import_id_fields = ('id',) skip_unchanged = True @admin.register(AuthorProfile) class AuthorProfileAdmin(ImportExportMixin, AccountAdminMixin, Igny8ModelAdmin): resource_class = AuthorProfileResource list_display = ['name', 'account', 'tone', 'language', 'is_active', 'created_at'] list_filter = ['is_active', 'tone', 'language', 'account'] search_fields = ['name', 'description', 'tone'] readonly_fields = ['created_at', 'updated_at'] actions = [ 'bulk_activate', 'bulk_deactivate', 'bulk_clone', ] fieldsets = ( ('Basic Info', { 'fields': ('account', 'name', 'description', 'is_active') }), ('Writing Style', { 'fields': ('tone', 'language', 'structure_template') }), ('Timestamps', { 'fields': ('created_at', 'updated_at') }), ) def get_account_display(self, obj): """Safely get account name""" try: account = getattr(obj, 'account', None) return account.name if account else '-' except: return '-' get_account_display.short_description = 'Account' def bulk_activate(self, request, queryset): updated = queryset.update(is_active=True) self.message_user(request, f'{updated} author profile(s) activated.', messages.SUCCESS) bulk_activate.short_description = 'Activate selected profiles' def bulk_deactivate(self, request, queryset): updated = queryset.update(is_active=False) self.message_user(request, f'{updated} author profile(s) deactivated.', messages.SUCCESS) bulk_deactivate.short_description = 'Deactivate selected profiles' def bulk_clone(self, request, queryset): count = 0 for profile in queryset: profile_copy = AuthorProfile.objects.get(pk=profile.pk) profile_copy.pk = None profile_copy.name = f"{profile.name} (Copy)" profile_copy.is_active = False profile_copy.save() count += 1 self.message_user(request, f'{count} author profile(s) cloned.', messages.SUCCESS) bulk_clone.short_description = 'Clone selected profiles' class StrategyResource(resources.ModelResource): """Resource class for importing/exporting Strategies""" class Meta: model = Strategy fields = ('id', 'name', 'account__name', 'sector__name', 'is_active', 'created_at') export_order = fields import_id_fields = ('id',) skip_unchanged = True @admin.register(Strategy) class StrategyAdmin(ImportExportMixin, AccountAdminMixin, Igny8ModelAdmin): resource_class = StrategyResource list_display = ['name', 'account', 'sector', 'is_active', 'created_at'] list_filter = ['is_active', 'account'] search_fields = ['name', 'description'] readonly_fields = ['created_at', 'updated_at'] actions = [ 'bulk_activate', 'bulk_deactivate', 'bulk_clone', ] fieldsets = ( ('Basic Info', { 'fields': ('account', 'name', 'description', 'sector', 'is_active') }), ('Strategy Configuration', { 'fields': ('prompt_types', 'section_logic') }), ('Timestamps', { 'fields': ('created_at', 'updated_at') }), ) def get_account_display(self, obj): """Safely get account name""" try: account = getattr(obj, 'account', None) return account.name if account else '-' except: return '-' get_account_display.short_description = 'Account' def get_sector_display(self, obj): """Safely get sector name""" try: return obj.sector.name if obj.sector else 'Global' except: return 'Global' get_sector_display.short_description = 'Sector' def bulk_activate(self, request, queryset): updated = queryset.update(is_active=True) self.message_user(request, f'{updated} strategy/strategies activated.', messages.SUCCESS) bulk_activate.short_description = 'Activate selected strategies' def bulk_deactivate(self, request, queryset): updated = queryset.update(is_active=False) self.message_user(request, f'{updated} strategy/strategies deactivated.', messages.SUCCESS) bulk_deactivate.short_description = 'Deactivate selected strategies' def bulk_clone(self, request, queryset): count = 0 for strategy in queryset: strategy_copy = Strategy.objects.get(pk=strategy.pk) strategy_copy.pk = None strategy_copy.name = f"{strategy.name} (Copy)" strategy_copy.is_active = False strategy_copy.save() count += 1 self.message_user(request, f'{count} strategy/strategies cloned.', messages.SUCCESS) bulk_clone.short_description = 'Clone selected strategies'