Files
OSINT/analytics/views.py
Iliyan Angelov ed94dd22dd update
2025-11-26 22:32:20 +02:00

175 lines
7.5 KiB
Python

"""
Views for analytics app.
"""
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.db.models import Count, Q, Avg, Max, Min
from django.utils import timezone
from django.utils.safestring import mark_safe
import json
from datetime import timedelta
from reports.models import ScamReport
from accounts.models import User, ActivityLog
from osint.models import OSINTTask
from moderation.models import ModerationAction
class AdminRequiredMixin(UserPassesTestMixin):
"""Mixin to require admin role."""
def test_func(self):
return self.request.user.is_authenticated and self.request.user.is_administrator()
class AnalyticsDashboardView(LoginRequiredMixin, AdminRequiredMixin, TemplateView):
"""Analytics dashboard."""
template_name = 'analytics/dashboard.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Report statistics
context['total_reports'] = ScamReport.objects.count()
context['pending_reports'] = ScamReport.objects.filter(status='pending').count()
context['verified_reports'] = ScamReport.objects.filter(status='verified').count()
context['rejected_reports'] = ScamReport.objects.filter(status='rejected').count()
# Scam type breakdown with display names and percentages
scam_types_data = ScamReport.objects.values('scam_type').annotate(
count=Count('id')
).order_by('-count')
scam_types_list = []
total_reports = context.get('total_reports', 0)
for item in scam_types_data:
scam_type_key = item['scam_type']
display_name = dict(ScamReport.SCAM_TYPE_CHOICES).get(scam_type_key, scam_type_key)
percentage = (item['count'] / total_reports * 100) if total_reports > 0 else 0
scam_types_list.append({
'scam_type': scam_type_key,
'display_name': display_name,
'count': item['count'],
'percentage': round(percentage, 1)
})
context['scam_types'] = scam_types_list
# User statistics
context['total_users'] = User.objects.count()
context['moderators'] = User.objects.filter(role__in=['moderator', 'admin']).count()
# OSINT statistics
context['osint_tasks'] = OSINTTask.objects.count()
context['completed_tasks'] = OSINTTask.objects.filter(status='completed').count()
return context
class ReportAnalyticsView(LoginRequiredMixin, AdminRequiredMixin, TemplateView):
"""Report analytics."""
template_name = 'analytics/reports.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Overall statistics
context['total_reports'] = ScamReport.objects.count()
context['pending_reports'] = ScamReport.objects.filter(status='pending').count()
context['verified_reports'] = ScamReport.objects.filter(status='verified').count()
context['rejected_reports'] = ScamReport.objects.filter(status='rejected').count()
context['under_review_reports'] = ScamReport.objects.filter(status='under_review').count()
# Scam type distribution
scam_types_data = ScamReport.objects.values('scam_type').annotate(
count=Count('id')
).order_by('-count')
scam_types_list = []
for item in scam_types_data:
scam_type_key = item['scam_type']
display_name = dict(ScamReport.SCAM_TYPE_CHOICES).get(scam_type_key, scam_type_key)
percentage = (item['count'] / context['total_reports'] * 100) if context['total_reports'] > 0 else 0
scam_types_list.append({
'scam_type': scam_type_key,
'display_name': display_name,
'count': item['count'],
'percentage': round(percentage, 1)
})
context['scam_types'] = scam_types_list
# Time-based statistics
now = timezone.now()
last_7_days = now - timedelta(days=7)
last_30_days = now - timedelta(days=30)
last_90_days = now - timedelta(days=90)
context['reports_last_7_days'] = ScamReport.objects.filter(created_at__gte=last_7_days).count()
context['reports_last_30_days'] = ScamReport.objects.filter(created_at__gte=last_30_days).count()
context['reports_last_90_days'] = ScamReport.objects.filter(created_at__gte=last_90_days).count()
# Daily reports for the last 30 days
daily_reports = []
for i in range(29, -1, -1): # From 29 days ago to today
date = now - timedelta(days=i)
count = ScamReport.objects.filter(
created_at__date=date.date()
).count()
daily_reports.append({
'date': date.date().isoformat(),
'count': count
})
context['daily_reports'] = mark_safe(json.dumps(daily_reports))
# Average moderation time
verified_reports = ScamReport.objects.filter(
status='verified',
verified_at__isnull=False
)
if verified_reports.exists():
moderation_times = []
for report in verified_reports:
if report.created_at and report.verified_at:
time_diff = report.verified_at - report.created_at
moderation_times.append(time_diff.total_seconds() / 3600) # Convert to hours
if moderation_times:
context['avg_moderation_time_hours'] = round(sum(moderation_times) / len(moderation_times), 2)
context['min_moderation_time_hours'] = round(min(moderation_times), 2)
context['max_moderation_time_hours'] = round(max(moderation_times), 2)
# Top reporters
top_reporters = ScamReport.objects.values(
'reporter__username',
'reporter__email'
).annotate(
report_count=Count('id')
).order_by('-report_count')[:10]
context['top_reporters'] = top_reporters
# Moderation statistics
context['total_moderations'] = ModerationAction.objects.count()
context['approvals'] = ModerationAction.objects.filter(action_type='approve').count()
context['rejections'] = ModerationAction.objects.filter(action_type='reject').count()
# Reports by status over time
status_over_time = []
for i in range(6, -1, -1): # From 6 days ago to today
date = now - timedelta(days=i)
status_over_time.append({
'date': date.date().isoformat(),
'pending': ScamReport.objects.filter(status='pending', created_at__date=date.date()).count(),
'verified': ScamReport.objects.filter(status='verified', created_at__date=date.date()).count(),
'rejected': ScamReport.objects.filter(status='rejected', created_at__date=date.date()).count(),
})
context['status_over_time'] = mark_safe(json.dumps(status_over_time))
return context
class UserAnalyticsView(LoginRequiredMixin, AdminRequiredMixin, TemplateView):
"""User analytics."""
template_name = 'analytics/users.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Add detailed user analytics
return context