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

248 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Admin configuration for reports app.
"""
from django.contrib import admin
from django.utils.html import format_html
from django import forms
from .models import ScamTag, ScamReport, ScamVerification, SiteSettings, TakedownRequest
@admin.register(ScamTag)
class ScamTagAdmin(admin.ModelAdmin):
"""Scam tag admin."""
list_display = ('name', 'slug', 'color')
prepopulated_fields = {'slug': ('name',)}
search_fields = ('name',)
@admin.register(ScamReport)
class ScamReportAdmin(admin.ModelAdmin):
"""Scam report admin."""
list_display = ('title', 'reporter', 'scam_type', 'status', 'verification_score', 'created_at')
list_filter = ('status', 'scam_type', 'is_public', 'created_at')
search_fields = ('title', 'description', 'reported_url', 'reported_email', 'reported_phone')
readonly_fields = ('created_at', 'updated_at', 'verified_at', 'reporter_ip')
filter_horizontal = ('tags',)
date_hierarchy = 'created_at'
fieldsets = (
('Report Information', {
'fields': ('title', 'description', 'scam_type', 'tags')
}),
('Reported Entities', {
'fields': ('reported_url', 'reported_email', 'reported_phone', 'reported_company')
}),
('Reporter', {
'fields': ('reporter', 'is_anonymous', 'reporter_ip')
}),
('Status', {
'fields': ('status', 'verification_score', 'is_public', 'verified_at')
}),
('Evidence', {
'fields': ('evidence_files',)
}),
('Timestamps', {
'fields': ('created_at', 'updated_at')
}),
)
@admin.register(ScamVerification)
class ScamVerificationAdmin(admin.ModelAdmin):
"""Scam verification admin."""
list_display = ('report', 'verification_method', 'confidence_score', 'verified_by', 'created_at')
list_filter = ('verification_method', 'created_at')
search_fields = ('report__title', 'notes')
readonly_fields = ('created_at',)
@admin.register(SiteSettings)
class SiteSettingsAdmin(admin.ModelAdmin):
"""Site settings admin - singleton pattern."""
def has_add_permission(self, request):
# Only allow one instance
return not SiteSettings.objects.exists()
def has_delete_permission(self, request, obj=None):
# Prevent deletion
return False
fieldsets = (
('Контактна Информация', {
'fields': ('contact_email', 'contact_phone', 'contact_address'),
'description': 'Тези настройки се използват навсякъде в сайта - в подножието, страницата за контакти, структурираните данни и др.'
}),
('Настройки на Имейл Сървър', {
'fields': (
'email_backend',
'email_host',
'email_port',
'email_use_tls',
'email_use_ssl',
'email_host_user',
'email_host_password',
'default_from_email',
'email_timeout',
),
'description': 'Настройки за SMTP сървър. Използват се за всички имейли в платформата - контактни форми, нулиране на пароли, уведомления и др. Паролата се криптира автоматично.'
}),
('Информация', {
'fields': ('updated_at',),
'classes': ('collapse',)
}),
)
readonly_fields = ('updated_at',)
def get_form(self, request, obj=None, **kwargs):
"""Customize form to handle password field."""
form = super().get_form(request, obj, **kwargs)
# Make password field a password input
form.base_fields['email_host_password'].widget = forms.PasswordInput(attrs={
'class': 'vTextField',
'autocomplete': 'new-password'
})
# Add help text
form.base_fields['email_host_password'].help_text = 'Въведете нова парола или оставете празно, за да запазите текущата.'
return form
def save_model(self, request, obj, form, change):
"""Handle password encryption and clear cache."""
# If password field is empty and we're editing, keep the old password
if change and not form.cleaned_data.get('email_host_password'):
old_obj = self.model.objects.get(pk=obj.pk)
obj.email_host_password = old_obj.email_host_password
# Validate TLS/SSL are mutually exclusive
if obj.email_use_tls and obj.email_use_ssl:
from django.contrib import messages
messages.warning(request, 'TLS и SSL не могат да бъдат активирани едновременно. SSL е деактивиран, използва се TLS.')
obj.email_use_ssl = False
# Save will encrypt the password if it's provided
super().save_model(request, obj, form, change)
# Clear email backend cache to reload settings
from django.core.cache import cache
cache.delete('site_settings')
def changelist_view(self, request, extra_context=None):
# Redirect to the single instance if it exists
from django.shortcuts import redirect
from django.urls import reverse
if SiteSettings.objects.exists():
obj = SiteSettings.objects.get(pk=1)
url = reverse('admin:reports_sitesettings_change', args=[str(obj.pk)])
return redirect(url)
return super().changelist_view(request, extra_context)
def response_change(self, request, obj):
"""Handle test email button."""
if "_test_email" in request.POST:
try:
from django.core.mail import send_mail
from django.contrib import messages
test_email = request.POST.get('test_email_address', request.user.email)
if not test_email:
messages.error(request, 'Моля, въведете имейл адрес за тест.')
return super().response_change(request, obj)
# Check if SMTP is configured
if obj.email_backend == 'django.core.mail.backends.smtp.EmailBackend' and not obj.email_host:
messages.warning(request, 'SMTP сървърът не е конфигуриран. Моля, въведете Email Host преди изпращане на тестов имейл.')
return super().response_change(request, obj)
# Get the connection to check backend type
from django.core.mail import get_connection, EmailMessage
connection = get_connection()
backend_name = connection.__class__.__name__
import logging
logger = logging.getLogger(__name__)
logger.info(f"Using email backend: {backend_name}")
# Check underlying backend
if hasattr(connection, '_backend') and connection._backend:
underlying_backend = connection._backend.__class__.__name__
logger.info(f"Underlying backend: {underlying_backend}")
# Send email using EmailMessage for better error handling
email = EmailMessage(
subject='Тестов Имейл от Портал за Докладване на Измами',
body='Това е тестов имейл за проверка на настройките на имейл сървъра. Ако получавате този имейл, настройките са правилни.',
from_email=obj.default_from_email,
to=[test_email],
connection=connection,
)
result = email.send(fail_silently=False)
logger.info(f"Email send result: {result} (1 = success, 0 = failed)")
# Check which backend was actually used
if 'Console' in backend_name or 'console' in str(connection.__class__.__module__):
messages.warning(request, f'Имейлът е изпратен чрез конзолен backend (за разработка). За реално изпращане, конфигурирайте SMTP настройките. Backend: {backend_name}')
else:
messages.success(request, f'Тестов имейл изпратен успешно до {test_email}! Използван backend: {backend_name}')
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.exception("Error sending test email")
error_msg = str(e)
if 'authentication failed' in error_msg.lower():
messages.error(request, f'Грешка при удостоверяване: Проверете потребителското име и паролата.')
elif 'connection' in error_msg.lower() or 'timeout' in error_msg.lower():
messages.error(request, f'Грешка при свързване: Проверете SMTP сървъра и порта.')
else:
messages.error(request, f'Грешка при изпращане на тестов имейл: {error_msg}')
return super().response_change(request, obj)
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
extra_context = extra_context or {}
if object_id:
obj = self.get_object(request, object_id)
if obj:
extra_context['show_test_email'] = True
return super().changeform_view(request, object_id, form_url, extra_context)
@admin.register(TakedownRequest)
class TakedownRequestAdmin(admin.ModelAdmin):
"""Takedown request admin."""
list_display = ('report', 'requester_name', 'requester_email', 'status', 'created_at', 'reviewed_by')
list_filter = ('status', 'created_at', 'reviewed_at')
search_fields = ('requester_name', 'requester_email', 'report__title', 'reason')
readonly_fields = ('created_at', 'updated_at', 'ip_address', 'user_agent')
date_hierarchy = 'created_at'
fieldsets = (
('Информация за Доклада', {
'fields': ('report',)
}),
('Информация за Заявителя', {
'fields': ('requester_name', 'requester_email', 'requester_phone')
}),
('Детайли на Заявката', {
'fields': ('reason', 'evidence')
}),
('Статус и Преглед', {
'fields': ('status', 'reviewed_by', 'review_notes', 'reviewed_at')
}),
('Техническа Информация', {
'fields': ('ip_address', 'user_agent', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def save_model(self, request, obj, form, change):
if change and 'status' in form.changed_data and obj.status in ['approved', 'rejected']:
from django.utils import timezone
obj.reviewed_by = request.user
obj.reviewed_at = timezone.now()
super().save_model(request, obj, form, change)