143 lines
5.9 KiB
Python
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
|