Files
igny8/backend/igny8_core/modules/system/admin.py
2025-12-20 02:46:00 +00:00

315 lines
12 KiB
Python

"""
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'