from django.contrib.auth.models import AbstractUser from django.db import models from django.utils import timezone from cryptography.fernet import Fernet import os class User(AbstractUser): """Custom User model with additional fields for email functionality.""" email = models.EmailField(unique=True) first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) avatar = models.ImageField(upload_to='avatars/', null=True, blank=True) is_verified = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) last_login_ip = models.GenericIPAddressField(null=True, blank=True) # Email server settings smtp_host = models.CharField(max_length=255, blank=True) smtp_port = models.IntegerField(default=587) smtp_username = models.CharField(max_length=255, blank=True) smtp_password = models.BinaryField(blank=True) # Encrypted smtp_use_tls = models.BooleanField(default=True) imap_host = models.CharField(max_length=255, blank=True) imap_port = models.IntegerField(default=993) imap_username = models.CharField(max_length=255, blank=True) imap_password = models.BinaryField(blank=True) # Encrypted imap_use_ssl = models.BooleanField(default=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username', 'first_name', 'last_name'] class Meta: db_table = 'users' def __str__(self): return self.email def get_full_name(self): return f"{self.first_name} {self.last_name}".strip() def get_short_name(self): return self.first_name def encrypt_password(self, password): """Encrypt password for storage.""" key = os.environ.get('ENCRYPTION_KEY', Fernet.generate_key()) f = Fernet(key) return f.encrypt(password.encode()) def decrypt_password(self, encrypted_password): """Decrypt password for use.""" if not encrypted_password: return None key = os.environ.get('ENCRYPTION_KEY', Fernet.generate_key()) f = Fernet(key) return f.decrypt(encrypted_password).decode() def set_smtp_password(self, password): """Set encrypted SMTP password.""" self.smtp_password = self.encrypt_password(password) def get_smtp_password(self): """Get decrypted SMTP password.""" return self.decrypt_password(self.smtp_password) def set_imap_password(self, password): """Set encrypted IMAP password.""" self.imap_password = self.encrypt_password(password) def get_imap_password(self): """Get decrypted IMAP password.""" return self.decrypt_password(self.imap_password) class UserProfile(models.Model): """Extended user profile information.""" user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') signature = models.TextField(blank=True) auto_reply_enabled = models.BooleanField(default=False) auto_reply_message = models.TextField(blank=True) timezone = models.CharField(max_length=50, default='UTC') language = models.CharField(max_length=10, default='en') theme = models.CharField(max_length=20, default='light') # Email preferences emails_per_page = models.IntegerField(default=20) auto_save_drafts = models.BooleanField(default=True) show_images = models.BooleanField(default=True) mark_as_read_delay = models.IntegerField(default=3) # seconds created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: db_table = 'user_profiles' def __str__(self): return f"{self.user.email} Profile" class LoginAttempt(models.Model): """Track login attempts for security.""" user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) email = models.EmailField() ip_address = models.GenericIPAddressField() user_agent = models.TextField() success = models.BooleanField(default=False) failure_reason = models.CharField(max_length=100, blank=True) timestamp = models.DateTimeField(auto_now_add=True) class Meta: db_table = 'login_attempts' ordering = ['-timestamp'] def __str__(self): status = "Success" if self.success else "Failed" return f"{self.email} - {status} - {self.timestamp}" class EmailVerification(models.Model): """Email verification tokens.""" user = models.ForeignKey(User, on_delete=models.CASCADE) token = models.CharField(max_length=100, unique=True) created_at = models.DateTimeField(auto_now_add=True) expires_at = models.DateTimeField() is_used = models.BooleanField(default=False) class Meta: db_table = 'email_verifications' def __str__(self): return f"{self.user.email} - {self.token}" def is_expired(self): return timezone.now() > self.expires_at