django phase2.3.4.

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-14 15:10:41 +00:00
parent d161378bd9
commit eb88a0e12d
13 changed files with 2880 additions and 31 deletions

View File

@@ -0,0 +1,122 @@
"""
Admin Alert System
"""
from django.utils import timezone
from datetime import timedelta
class AdminAlerts:
"""System for admin alerts and notifications"""
@staticmethod
def get_alerts():
"""Get all active alerts"""
alerts = []
today = timezone.now().date()
# Check for pending payments
from igny8_core.business.billing.models import Payment
pending_payments = Payment.objects.filter(status='pending_approval').count()
if pending_payments > 0:
alerts.append({
'level': 'warning',
'icon': '⚠️',
'message': f'{pending_payments} payment(s) awaiting approval',
'url': '/admin/billing/payment/?status=pending_approval',
'action': 'Review Payments'
})
# Check for low credit accounts
from igny8_core.auth.models import Account
low_credit_accounts = Account.objects.filter(
status='active',
credits__lt=100
).count()
if low_credit_accounts > 0:
alerts.append({
'level': 'info',
'icon': '',
'message': f'{low_credit_accounts} account(s) with low credits',
'url': '/admin/igny8_core_auth/account/?credits__lt=100',
'action': 'View Accounts'
})
# Check for very low credits (critical)
critical_credit_accounts = Account.objects.filter(
status='active',
credits__lt=10
).count()
if critical_credit_accounts > 0:
alerts.append({
'level': 'error',
'icon': '🔴',
'message': f'{critical_credit_accounts} account(s) with critical low credits (< 10)',
'url': '/admin/igny8_core_auth/account/?credits__lt=10',
'action': 'Urgent Review'
})
# Check for failed automations
from igny8_core.business.automation.models import AutomationRun
failed_today = AutomationRun.objects.filter(
status='failed',
started_at__date=today
).count()
if failed_today > 0:
alerts.append({
'level': 'error',
'icon': '🔴',
'message': f'{failed_today} automation(s) failed today',
'url': '/admin/automation/automationrun/?status=failed',
'action': 'Review Failures'
})
# Check for failed syncs
from igny8_core.business.integration.models import SyncEvent
failed_syncs = SyncEvent.objects.filter(
success=False,
created_at__date=today
).count()
if failed_syncs > 5: # Only alert if more than 5
alerts.append({
'level': 'warning',
'icon': '⚠️',
'message': f'{failed_syncs} WordPress sync failures today',
'url': '/admin/integration/syncevent/?success=False',
'action': 'Review Syncs'
})
# Check for failed Celery tasks
try:
from django_celery_results.models import TaskResult
celery_failed = TaskResult.objects.filter(
status='FAILURE',
date_created__date=today
).count()
if celery_failed > 0:
alerts.append({
'level': 'error',
'icon': '🔴',
'message': f'{celery_failed} Celery task(s) failed today',
'url': '/admin/django_celery_results/taskresult/?status=FAILURE',
'action': 'Review Tasks'
})
except:
pass
# Check for stale pending tasks (older than 24 hours)
from igny8_core.modules.writer.models import Tasks
yesterday = today - timedelta(days=1)
stale_tasks = Tasks.objects.filter(
status='pending',
created_at__date__lte=yesterday
).count()
if stale_tasks > 10:
alerts.append({
'level': 'info',
'icon': '',
'message': f'{stale_tasks} tasks pending for more than 24 hours',
'url': '/admin/writer/tasks/?status=pending',
'action': 'Review Tasks'
})
return alerts

View File

@@ -39,5 +39,28 @@ class Igny8AdminConfig(AdminConfig):
_safe_register(Group, admin.ModelAdmin)
_safe_register(ContentType, ReadOnlyAdmin)
_safe_register(Session, ReadOnlyAdmin)
# Import and setup enhanced Celery task monitoring
self._setup_celery_admin()
def _setup_celery_admin(self):
"""Setup enhanced Celery admin with proper unregister/register"""
try:
from django_celery_results.models import TaskResult
from igny8_core.admin.celery_admin import CeleryTaskResultAdmin
# Unregister the default TaskResult admin
try:
admin.site.unregister(TaskResult)
except admin.sites.NotRegistered:
pass
# Register our enhanced version
admin.site.register(TaskResult, CeleryTaskResultAdmin)
except Exception as e:
# Log the error but don't crash the app
import logging
logger = logging.getLogger(__name__)
logger.warning(f"Could not setup enhanced Celery admin: {e}")

View File

@@ -0,0 +1,154 @@
"""
Celery Task Monitoring Admin
"""
from django.contrib import admin
from django.utils.html import format_html
from django.contrib import messages
from django_celery_results.models import TaskResult
from rangefilter.filters import DateRangeFilter
class CeleryTaskResultAdmin(admin.ModelAdmin):
"""Admin interface for monitoring Celery tasks"""
list_display = [
'task_id',
'task_name',
'colored_status',
'date_created',
'date_done',
'execution_time',
]
list_filter = [
'status',
'task_name',
('date_created', DateRangeFilter),
('date_done', DateRangeFilter),
]
search_fields = ['task_id', 'task_name', 'task_args']
readonly_fields = [
'task_id', 'task_name', 'task_args', 'task_kwargs',
'result', 'traceback', 'date_created', 'date_done',
'colored_status', 'execution_time'
]
date_hierarchy = 'date_created'
ordering = ['-date_created']
actions = ['retry_failed_tasks', 'clear_old_tasks']
fieldsets = (
('Task Information', {
'fields': ('task_id', 'task_name', 'colored_status')
}),
('Execution Details', {
'fields': ('date_created', 'date_done', 'execution_time')
}),
('Task Arguments', {
'fields': ('task_args', 'task_kwargs'),
'classes': ('collapse',)
}),
('Result & Errors', {
'fields': ('result', 'traceback'),
'classes': ('collapse',)
}),
)
def colored_status(self, obj):
"""Display status with color coding"""
colors = {
'SUCCESS': '#0bbf87', # IGNY8 success green
'FAILURE': '#ef4444', # IGNY8 danger red
'PENDING': '#ff7a00', # IGNY8 warning orange
'STARTED': '#0693e3', # IGNY8 primary blue
'RETRY': '#5d4ae3', # IGNY8 purple
}
color = colors.get(obj.status, '#64748b') # Default gray
return format_html(
'<span style="color: {}; font-weight: bold; font-size: 14px;">{}</span>',
color,
obj.status
)
colored_status.short_description = 'Status'
def execution_time(self, obj):
"""Calculate and display execution time"""
if obj.date_done and obj.date_created:
duration = obj.date_done - obj.date_created
seconds = duration.total_seconds()
if seconds < 1:
return format_html('<span style="color: #0bbf87;">{:.2f}ms</span>', seconds * 1000)
elif seconds < 60:
return format_html('<span style="color: #0693e3;">{:.2f}s</span>', seconds)
else:
minutes = seconds / 60
return format_html('<span style="color: #ff7a00;">{:.1f}m</span>', minutes)
return '-'
execution_time.short_description = 'Duration'
def retry_failed_tasks(self, request, queryset):
"""Retry failed celery tasks"""
from celery import current_app
failed_tasks = queryset.filter(status='FAILURE')
count = 0
errors = []
for task in failed_tasks:
try:
# Get task function
task_func = current_app.tasks.get(task.task_name)
if task_func:
# Parse task args and kwargs
import ast
try:
args = ast.literal_eval(task.task_args) if task.task_args else []
kwargs = ast.literal_eval(task.task_kwargs) if task.task_kwargs else {}
except:
args = []
kwargs = {}
# Retry the task
task_func.apply_async(args=args, kwargs=kwargs)
count += 1
else:
errors.append(f'Task function not found: {task.task_name}')
except Exception as e:
errors.append(f'Error retrying {task.task_id}: {str(e)}')
if count > 0:
self.message_user(request, f'✅ Retried {count} failed task(s)', messages.SUCCESS)
if errors:
for error in errors[:5]: # Show max 5 errors
self.message_user(request, f'⚠️ {error}', messages.WARNING)
retry_failed_tasks.short_description = '🔄 Retry Failed Tasks'
def clear_old_tasks(self, request, queryset):
"""Clear old completed tasks"""
from datetime import timedelta
from django.utils import timezone
# Delete tasks older than 30 days
cutoff_date = timezone.now() - timedelta(days=30)
old_tasks = queryset.filter(
date_created__lt=cutoff_date,
status__in=['SUCCESS', 'FAILURE']
)
count = old_tasks.count()
old_tasks.delete()
self.message_user(request, f'🗑️ Cleared {count} old task(s)', messages.SUCCESS)
clear_old_tasks.short_description = '🗑️ Clear Old Tasks (30+ days)'
def has_add_permission(self, request):
"""Disable manual task creation"""
return False
def has_change_permission(self, request, obj=None):
"""Make read-only"""
return False

View File

@@ -0,0 +1,112 @@
"""
Custom Admin Dashboard with Key Metrics
"""
from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import render
from django.db.models import Count, Sum, Q
from django.utils import timezone
from datetime import timedelta
@staff_member_required
def admin_dashboard(request):
"""Custom admin dashboard with operational metrics"""
# Date ranges
today = timezone.now().date()
week_ago = today - timedelta(days=7)
month_ago = today - timedelta(days=30)
# Account metrics
from igny8_core.auth.models import Account
total_accounts = Account.objects.count()
active_accounts = Account.objects.filter(status='active').count()
low_credit_accounts = Account.objects.filter(
status='active',
credits__lt=100
).count()
# Content metrics
from igny8_core.modules.writer.models import Content, Tasks
content_this_week = Content.objects.filter(created_at__gte=week_ago).count()
content_this_month = Content.objects.filter(created_at__gte=month_ago).count()
tasks_pending = Tasks.objects.filter(status='pending').count()
tasks_in_progress = Tasks.objects.filter(status='in_progress').count()
# Billing metrics
from igny8_core.business.billing.models import Payment, CreditTransaction
pending_payments = Payment.objects.filter(status='pending_approval').count()
payments_this_month = Payment.objects.filter(
created_at__gte=month_ago,
status='succeeded'
).aggregate(total=Sum('amount'))['total'] or 0
credit_usage_this_month = CreditTransaction.objects.filter(
created_at__gte=month_ago,
transaction_type='deduction'
).aggregate(total=Sum('amount'))['total'] or 0
# Automation metrics
from igny8_core.business.automation.models import AutomationRun
automation_running = AutomationRun.objects.filter(status='running').count()
automation_failed = AutomationRun.objects.filter(
status='failed',
started_at__gte=week_ago
).count()
# WordPress sync metrics
from igny8_core.business.integration.models import SyncEvent
sync_failed_today = SyncEvent.objects.filter(
success=False,
created_at__date=today
).count()
# Celery task metrics
try:
from django_celery_results.models import TaskResult
celery_failed = TaskResult.objects.filter(
status='FAILURE',
date_created__date=today
).count()
celery_pending = TaskResult.objects.filter(status='PENDING').count()
except:
celery_failed = 0
celery_pending = 0
# Get alerts
from .alerts import AdminAlerts
alerts = AdminAlerts.get_alerts()
context = {
'title': 'IGNY8 Dashboard',
'accounts': {
'total': total_accounts,
'active': active_accounts,
'low_credit': low_credit_accounts,
},
'content': {
'this_week': content_this_week,
'this_month': content_this_month,
'tasks_pending': tasks_pending,
'tasks_in_progress': tasks_in_progress,
},
'billing': {
'pending_payments': pending_payments,
'payments_this_month': float(payments_this_month),
'credit_usage_this_month': abs(credit_usage_this_month),
},
'automation': {
'running': automation_running,
'failed_this_week': automation_failed,
},
'integration': {
'sync_failed_today': sync_failed_today,
},
'celery': {
'failed_today': celery_failed,
'pending': celery_pending,
},
'alerts': alerts,
}
return render(request, 'admin/dashboard.html', context)

View File

@@ -4,6 +4,8 @@ Custom AdminSite for IGNY8 to organize models into proper groups
from django.contrib import admin
from django.contrib.admin.apps import AdminConfig
from django.apps import apps
from django.urls import path
from django.shortcuts import redirect
class Igny8AdminSite(admin.AdminSite):
@@ -20,6 +22,19 @@ class Igny8AdminSite(admin.AdminSite):
site_header = 'IGNY8 Administration'
site_title = 'IGNY8 Admin'
index_title = 'IGNY8 Administration'
def get_urls(self):
"""Add dashboard URL"""
urls = super().get_urls()
custom_urls = [
path('dashboard/', self.dashboard_view, name='dashboard'),
]
return custom_urls + urls
def dashboard_view(self, request):
"""Dashboard view wrapper"""
from igny8_core.admin.dashboard import admin_dashboard
return admin_dashboard(request)
def get_app_list(self, request):
"""
@@ -113,7 +128,13 @@ class Igny8AdminSite(admin.AdminSite):
('system', 'SystemStatus'),
],
},
'🔧 Django System': {
'<EFBFBD> Monitoring & Tasks': {
'models': [
('django_celery_results', 'TaskResult'),
('django_celery_results', 'GroupResult'),
],
},
'<EFBFBD>🔧 Django System': {
'models': [
('admin', 'LogEntry'),
('auth', 'Group'),