223 lines
8.3 KiB
Python
223 lines
8.3 KiB
Python
"""
|
|
Custom AdminSite for IGNY8 to organize models into proper groups using Unfold
|
|
NO EMOJIS - Unfold handles all icons via Material Design
|
|
"""
|
|
from django.contrib import admin
|
|
from django.contrib.admin.apps import AdminConfig
|
|
from django.apps import apps
|
|
from django.urls import path, reverse_lazy
|
|
from django.shortcuts import redirect
|
|
from django.contrib.admin import sites
|
|
from unfold.admin import ModelAdmin as UnfoldModelAdmin
|
|
from unfold.sites import UnfoldAdminSite
|
|
|
|
|
|
class Igny8AdminSite(UnfoldAdminSite):
|
|
"""
|
|
Custom AdminSite based on Unfold that organizes models into the planned groups
|
|
"""
|
|
site_header = 'IGNY8 Administration'
|
|
site_title = 'IGNY8 Admin'
|
|
index_title = 'IGNY8 Administration'
|
|
|
|
def get_urls(self):
|
|
"""Get admin URLs with dashboard available at /admin/dashboard/"""
|
|
from django.urls import path
|
|
from .dashboard import admin_dashboard
|
|
|
|
urls = super().get_urls()
|
|
custom_urls = [
|
|
path('dashboard/', self.admin_view(admin_dashboard), name='dashboard'),
|
|
]
|
|
return custom_urls + urls
|
|
|
|
def each_context(self, request):
|
|
"""
|
|
Override context to ensure our custom app_list is always used
|
|
This is called by all admin templates for sidebar rendering
|
|
|
|
CRITICAL FIX: Force custom sidebar on ALL pages including model detail/list views
|
|
"""
|
|
context = super().each_context(request)
|
|
# Force our custom app list to be used everywhere - IGNORE app_label parameter
|
|
custom_apps = self.get_app_list(request, app_label=None)
|
|
context['available_apps'] = custom_apps
|
|
context['app_list'] = custom_apps # Also set app_list for compatibility
|
|
return context
|
|
|
|
def get_app_list(self, request, app_label=None):
|
|
"""
|
|
Customize the app list to organize models into logical groups
|
|
NO EMOJIS - Unfold handles all icons via Material Design
|
|
|
|
Args:
|
|
request: The HTTP request
|
|
app_label: IGNORED - Always return full custom sidebar for consistency
|
|
"""
|
|
# CRITICAL: Always build full app_dict (ignore app_label) for consistent sidebar
|
|
app_dict = self._build_app_dict(request, None)
|
|
|
|
# Define our custom groups with their models (using object_name)
|
|
# Organized by business function - Material icons configured in Unfold
|
|
custom_groups = {
|
|
'Accounts & Users': {
|
|
'models': [
|
|
('igny8_core_auth', 'Account'),
|
|
('igny8_core_auth', 'User'),
|
|
('igny8_core_auth', 'Site'),
|
|
('igny8_core_auth', 'Sector'),
|
|
('igny8_core_auth', 'SiteUserAccess'),
|
|
('igny8_core_auth', 'Plan'),
|
|
('igny8_core_auth', 'Subscription'),
|
|
('igny8_core_auth', 'PasswordResetToken'),
|
|
('igny8_core_auth', 'Industry'),
|
|
('igny8_core_auth', 'IndustrySector'),
|
|
('igny8_core_auth', 'SeedKeyword'),
|
|
],
|
|
},
|
|
'Billing & Tenancy': {
|
|
'models': [
|
|
('billing', 'Invoice'),
|
|
('billing', 'Payment'),
|
|
('billing', 'CreditTransaction'),
|
|
('billing', 'CreditUsageLog'),
|
|
('billing', 'CreditPackage'),
|
|
('billing', 'PaymentMethodConfig'),
|
|
('billing', 'AccountPaymentMethod'),
|
|
('billing', 'CreditCostConfig'),
|
|
('billing', 'PlanLimitUsage'),
|
|
],
|
|
},
|
|
'Writer Module': {
|
|
'models': [
|
|
('writer', 'Content'),
|
|
('writer', 'Tasks'),
|
|
('writer', 'Images'),
|
|
('writer', 'ContentTaxonomy'),
|
|
('writer', 'ContentAttribute'),
|
|
('writer', 'ContentTaxonomyRelation'),
|
|
('writer', 'ContentClusterMap'),
|
|
],
|
|
},
|
|
'Planner': {
|
|
'models': [
|
|
('planner', 'Clusters'),
|
|
('planner', 'Keywords'),
|
|
('planner', 'ContentIdeas'),
|
|
],
|
|
},
|
|
'Publishing': {
|
|
'models': [
|
|
('publishing', 'PublishingRecord'),
|
|
('publishing', 'DeploymentRecord'),
|
|
],
|
|
},
|
|
'Optimization': {
|
|
'models': [
|
|
('optimization', 'OptimizationTask'),
|
|
],
|
|
},
|
|
'Automation': {
|
|
'models': [
|
|
('automation', 'AutomationConfig'),
|
|
('automation', 'AutomationRun'),
|
|
],
|
|
},
|
|
'Integration': {
|
|
'models': [
|
|
('integration', 'SiteIntegration'),
|
|
('integration', 'SyncEvent'),
|
|
],
|
|
},
|
|
'AI Framework': {
|
|
'models': [
|
|
('ai', 'AITaskLog'),
|
|
],
|
|
},
|
|
'System Configuration': {
|
|
'models': [
|
|
('system', 'AIPrompt'),
|
|
('system', 'Strategy'),
|
|
('system', 'AuthorProfile'),
|
|
('system', 'ContentTemplate'),
|
|
('system', 'TaxonomyConfig'),
|
|
('system', 'SystemSetting'),
|
|
('system', 'ContentTypeConfig'),
|
|
('system', 'PublishingChannel'),
|
|
('system', 'APIKey'),
|
|
('system', 'WebhookConfig'),
|
|
('system', 'NotificationConfig'),
|
|
('system', 'AuditLog'),
|
|
],
|
|
},
|
|
'Celery Results': {
|
|
'models': [
|
|
('django_celery_results', 'TaskResult'),
|
|
('django_celery_results', 'GroupResult'),
|
|
],
|
|
},
|
|
'Content Types': {
|
|
'models': [
|
|
('contenttypes', 'ContentType'),
|
|
],
|
|
},
|
|
'Administration': {
|
|
'models': [
|
|
('admin', 'LogEntry'),
|
|
],
|
|
},
|
|
'Authentication and Authorization': {
|
|
'models': [
|
|
('auth', 'Group'),
|
|
('auth', 'Permission'),
|
|
],
|
|
},
|
|
'Sessions': {
|
|
'models': [
|
|
('sessions', 'Session'),
|
|
],
|
|
},
|
|
}
|
|
|
|
# ALWAYS build and return our custom organized app list
|
|
# regardless of app_label parameter (for consistent sidebar on all pages)
|
|
organized_apps = []
|
|
|
|
# Add Dashboard link as first item
|
|
organized_apps.append({
|
|
'name': '📊 Dashboard',
|
|
'app_label': '_dashboard',
|
|
'app_url': '/admin/dashboard/',
|
|
'has_module_perms': True,
|
|
'models': [],
|
|
})
|
|
|
|
for group_name, group_config in custom_groups.items():
|
|
group_models = []
|
|
|
|
for app_label, model_name in group_config['models']:
|
|
# Find the model in app_dict
|
|
for app in app_dict.values():
|
|
if app['app_label'] == app_label:
|
|
for model in app.get('models', []):
|
|
if model['object_name'] == model_name:
|
|
group_models.append(model)
|
|
break
|
|
|
|
if group_models:
|
|
# Get the first model's app_label to use as the real app_label
|
|
first_model_app_label = group_config['models'][0][0]
|
|
organized_apps.append({
|
|
'name': group_name,
|
|
'app_label': first_model_app_label, # Use real app_label, not fake one
|
|
'app_url': f'/admin/{first_model_app_label}/', # Real URL, not '#'
|
|
'has_module_perms': True,
|
|
'models': group_models,
|
|
})
|
|
|
|
return organized_apps
|
|
|
|
|
|
# Instantiate custom admin site
|
|
admin_site = Igny8AdminSite(name='admin')
|