from typing import List, Dict, Optional from datetime import datetime from app.models import db, ProcessedEmail, User, Folder from sqlalchemy import and_, or_ class ProcessedEmailsService: def __init__(self, user: User): self.user = user def get_pending_emails(self, folder_name: str) -> List[str]: """Get list of email UIDs that are pending processing in a folder.""" try: pending_emails = ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name, is_processed=False ).all() return [email.email_uid for email in pending_emails] except Exception as e: print(f"Error getting pending emails: {str(e)}") return [] def mark_email_processed(self, folder_name: str, email_uid: str) -> bool: """Mark an email as processed.""" try: processed_email = ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name, email_uid=email_uid ).first() if processed_email: processed_email.is_processed = True processed_email.processed_at = datetime.utcnow() processed_email.updated_at = datetime.utcnow() db.session.commit() return True else: # Get the folder object to set the folder_id folder = Folder.query.filter_by( user_id=self.user.id, name=folder_name ).first() if folder: # Create a new record if it doesn't exist new_record = ProcessedEmail( user_id=self.user.id, folder_id=folder.id, folder_name=folder_name, email_uid=email_uid, is_processed=True, processed_at=datetime.utcnow() ) db.session.add(new_record) db.session.commit() return True else: return False except Exception as e: print(f"Error marking email as processed: {str(e)}") db.session.rollback() return False def mark_emails_processed(self, folder_name: str, email_uids: List[str]) -> int: """Mark multiple emails as processed in bulk.""" try: updated_count = 0 # Update existing records ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name, is_processed=False ).filter(ProcessedEmail.email_uid.in_(email_uids)).update( { 'is_processed': True, 'processed_at': datetime.utcnow(), 'updated_at': datetime.utcnow() }, synchronize_session=False ) # Check for any email UIDs that don't have records yet existing_uids = {email.email_uid for email in ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name ).all()} missing_uids = set(email_uids) - existing_uids if missing_uids: # Get the folder object to set the folder_id folder = Folder.query.filter_by( user_id=self.user.id, name=folder_name ).first() if folder: # Create new records for missing UIDs new_records = [ ProcessedEmail( user_id=self.user.id, folder_id=folder.id, folder_name=folder_name, email_uid=uid, is_processed=True, processed_at=datetime.utcnow() ) for uid in missing_uids ] db.session.bulk_save_objects(new_records) updated_count = len(email_uids) db.session.commit() return updated_count except Exception as e: print(f"Error marking emails as processed: {str(e)}") db.session.rollback() return 0 def sync_folder_emails(self, folder_name: str, email_uids: List[str]) -> int: """Sync email UIDs for a folder, adding new ones as pending.""" try: # Get existing UIDs for this folder existing_uids = {email.email_uid for email in ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name ).all()} # Find new UIDs that don't exist yet new_uids = set(email_uids) - existing_uids # Create new records for new UIDs if new_uids: # Get the folder object to set the folder_id folder = Folder.query.filter_by( user_id=self.user.id, name=folder_name ).first() if folder: new_records = [ ProcessedEmail( user_id=self.user.id, folder_id=folder.id, folder_name=folder_name, email_uid=uid, is_processed=False ) for uid in new_uids ] db.session.bulk_save_objects(new_records) # Get the folder to update counts folder = Folder.query.filter_by( user_id=self.user.id, name=folder_name ).first() if folder: # Update pending count pending_count = ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name, is_processed=False ).count() folder.pending_count = pending_count folder.total_count = len(email_uids) db.session.commit() return len(new_uids) except Exception as e: print(f"Error syncing folder emails: {str(e)}") db.session.rollback() return 0 def get_pending_count(self, folder_name: str) -> int: """Get count of pending emails for a folder.""" try: count = ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name, is_processed=False ).count() return count except Exception as e: print(f"Error getting pending count: {str(e)}") return 0 def cleanup_old_records(self, folder_name: str, current_uids: List[str]) -> int: """Remove records for emails that no longer exist in the folder.""" try: # Find records that no longer exist in the current UIDs records_to_delete = ProcessedEmail.query.filter( and_( ProcessedEmail.user_id == self.user.id, ProcessedEmail.folder_name == folder_name, ~ProcessedEmail.email_uid.in_(current_uids) ) ).all() # Delete the records for record in records_to_delete: db.session.delete(record) deleted_count = len(records_to_delete) db.session.commit() # Update folder counts after cleanup folder = Folder.query.filter_by( user_id=self.user.id, name=folder_name ).first() if folder: pending_count = ProcessedEmail.query.filter_by( user_id=self.user.id, folder_name=folder_name, is_processed=False ).count() folder.pending_count = pending_count folder.total_count = len(current_uids) db.session.commit() return deleted_count except Exception as e: print(f"Error cleaning up old records: {str(e)}") db.session.rollback() return 0