Site/programmer/admin.py

143 lines
5.9 KiB
Python

from django.contrib import admin
from django.utils import timezone
from django.utils.html import format_html
from django.urls import path
from django.shortcuts import render
from django.contrib import messages
from .models import Home, Solution, Competence, Recall, CallbackRequest, PageView
# ===== BASE ADMIN CLASSES =====
class BaseContentAdmin(admin.ModelAdmin):
"""Общий базовый класс для контентных моделей."""
list_display_links = ('id', 'title')
list_editable = ('is_published',)
list_filter = ('time_create', 'is_published')
search_fields = ('title',)
# ===== MODEL ADMINS =====
@admin.register(Home)
class HomeAdmin(BaseContentAdmin):
list_display = ('id', 'title', 'time_create', 'is_published')
search_fields = ('title', 'content')
@admin.register(Solution)
class SolutionAdmin(BaseContentAdmin):
list_display = ('id', 'title', 'time_create', 'is_published')
search_fields = ('title', 'description', 'implementation')
@admin.register(Competence)
class CompetenceAdmin(BaseContentAdmin):
list_display = ('id', 'title', 'time_create', 'is_published')
search_fields = ('title', 'content')
@admin.register(Recall)
class RecallAdmin(BaseContentAdmin):
list_display = ('id', 'title', 'time_create', 'scan', 'is_published')
search_fields = ('title', 'content')
@admin.register(CallbackRequest)
class CallbackAdmin(admin.ModelAdmin):
list_display = ('name', 'phone', 'email', 'time_create', 'is_processed', 'is_read', 'new_badge')
list_display_links = ('name', 'phone')
list_editable = ('is_processed', 'is_read')
list_filter = ('time_create', 'is_processed', 'is_read')
search_fields = ('name', 'phone', 'email')
readonly_fields = ('time_create',)
actions = ['mark_as_read', 'mark_as_unread', 'mark_as_processed', 'resend_notification']
# ── badge helper ──────────────────────────────────────────────────────────
def new_badge(self, obj):
if not obj.is_read:
return format_html('<span style="color:red;font-weight:bold;">🆕 НОВАЯ</span>')
return ''
new_badge.short_description = 'Статус'
# ── bulk actions ──────────────────────────────────────────────────────────
def mark_as_read(self, request, queryset):
updated = queryset.update(is_read=True)
self.message_user(request, f'{updated} заявок отмечены как прочитанные')
mark_as_read.short_description = 'Отметить как прочитанные'
def mark_as_unread(self, request, queryset):
updated = queryset.update(is_read=False)
self.message_user(request, f'{updated} заявок отмечены как непрочитанные')
mark_as_unread.short_description = 'Отметить как непрочитанные'
def mark_as_processed(self, request, queryset):
updated = queryset.update(is_processed=True)
self.message_user(request, f'{updated} заявок отмечены как обработанные')
mark_as_processed.short_description = 'Отметить как обработанные'
def resend_notification(self, request, queryset):
from .utils.email_notifications import send_multiple_callback_notifications
count = send_multiple_callback_notifications(queryset)
self.message_user(request, f'Уведомления отправлены для {count} заявок')
resend_notification.short_description = 'Переотправить email уведомления'
# ── custom URL + view for stats ───────────────────────────────────────────
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path(
'callback-stats/',
self.admin_site.admin_view(self.callback_stats_view),
name='callback_stats',
),
]
return custom_urls + urls
def callback_stats_view(self, request):
today = timezone.now().date()
week_ago = today - timezone.timedelta(days=7)
stats = {
'total': CallbackRequest.objects.count(),
'today': CallbackRequest.objects.filter(time_create__date=today).count(),
'week': CallbackRequest.objects.filter(time_create__date__gte=week_ago).count(),
'unread': CallbackRequest.objects.filter(is_read=False).count(),
'unprocessed': CallbackRequest.objects.filter(is_processed=False).count(),
}
context = {
**self.admin_site.each_context(request),
'title': 'Статистика заявок',
'stats': stats,
}
return render(request, 'admin/callback_stats.html', context)
# ── FIX: removed get_queryset message_user spam ───────────────────────────
# Previously, a warning banner was shown on EVERY request to the changelist,
# including background requests. Removed entirely — the new_badge column
# and base_site.html header notification already surface unread counts.
@admin.register(PageView)
class PageViewAdmin(admin.ModelAdmin):
list_display = ('url', 'timestamp', 'ip_address')
list_filter = ('timestamp', 'url')
search_fields = ('url', 'ip_address')
date_hierarchy = 'timestamp'
readonly_fields = ('url', 'timestamp', 'ip_address')
def get_queryset(self, request):
return super().get_queryset(request).order_by('-timestamp')
# PageViews should never be created or edited manually
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False