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

176 lines
5.2 KiB
Python

"""
User management models for the fraud reporting platform.
"""
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
from django.core.validators import RegexValidator
class User(AbstractUser):
"""
Custom user model with role-based access control.
"""
ROLE_CHOICES = [
('normal', 'Normal User'),
('moderator', 'Moderator'),
('admin', 'Administrator'),
]
role = models.CharField(
max_length=20,
choices=ROLE_CHOICES,
default='normal',
help_text='User role in the system'
)
is_verified = models.BooleanField(
default=False,
help_text='Email verification status'
)
mfa_enabled = models.BooleanField(
default=False,
help_text='Multi-factor authentication enabled'
)
mfa_secret = models.CharField(
max_length=32,
blank=True,
null=True,
help_text='MFA secret key'
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
last_login_ip = models.GenericIPAddressField(null=True, blank=True)
class Meta:
db_table = 'users_user'
verbose_name = 'User'
verbose_name_plural = 'Users'
ordering = ['-created_at']
def __str__(self):
return f"{self.username} ({self.role})"
def is_moderator(self):
return self.role in ['moderator', 'admin']
def is_administrator(self):
return self.role == 'admin'
class UserProfile(models.Model):
"""
Extended user profile information.
"""
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
related_name='profile'
)
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
phone_regex = RegexValidator(
regex=r'^\+?1?\d{9,15}$',
message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed."
)
phone = models.CharField(
validators=[phone_regex],
max_length=17,
blank=True,
null=True,
help_text='Encrypted phone number'
)
date_of_birth = models.DateField(null=True, blank=True)
# GDPR Consent
consent_given = models.BooleanField(default=False)
consent_date = models.DateTimeField(null=True, blank=True)
consent_ip = models.GenericIPAddressField(null=True, blank=True)
# Preferences
preferred_language = models.CharField(
max_length=10,
default='bg',
choices=[('bg', 'Bulgarian'), ('en', 'English')]
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'users_userprofile'
verbose_name = 'User Profile'
verbose_name_plural = 'User Profiles'
def __str__(self):
return f"Profile of {self.user.username}"
class ActivityLog(models.Model):
"""
Log user activities for security and auditing.
"""
ACTION_CHOICES = [
('login', 'Login'),
('logout', 'Logout'),
('register', 'Registration'),
('password_change', 'Password Change'),
('profile_update', 'Profile Update'),
('report_create', 'Report Created'),
('report_edit', 'Report Edited'),
('report_delete', 'Report Deleted'),
('security_event', 'Security Event'),
('failed_login', 'Failed Login'),
('suspicious_activity', 'Suspicious Activity'),
]
user = models.ForeignKey(
User,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='activity_logs'
)
action = models.CharField(max_length=50, choices=ACTION_CHOICES)
ip_address = models.GenericIPAddressField(null=True, blank=True)
user_agent = models.TextField(blank=True)
details = models.JSONField(default=dict, blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'users_activitylog'
verbose_name = 'Activity Log'
verbose_name_plural = 'Activity Logs'
ordering = ['-timestamp']
indexes = [
models.Index(fields=['user', 'timestamp']),
models.Index(fields=['action', 'timestamp']),
]
def __str__(self):
return f"{self.user} - {self.action} at {self.timestamp}"
class FailedLoginAttempt(models.Model):
"""
Track failed login attempts for security.
"""
email_or_username = models.CharField(max_length=255)
ip_address = models.GenericIPAddressField()
user_agent = models.TextField(blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
is_blocked = models.BooleanField(default=False)
class Meta:
db_table = 'security_failedlogin'
verbose_name = 'Failed Login Attempt'
verbose_name_plural = 'Failed Login Attempts'
ordering = ['-timestamp']
indexes = [
models.Index(fields=['email_or_username', 'timestamp']),
models.Index(fields=['ip_address', 'timestamp']),
]
def __str__(self):
return f"Failed login: {self.email_or_username} from {self.ip_address}"