181 lines
7.5 KiB
Python
181 lines
7.5 KiB
Python
import sys
|
|
import os
|
|
import subprocess
|
|
from app import create_app, db
|
|
from app.models import Folder, User, ProcessedEmail
|
|
from app.imap_service import IMAPService
|
|
from app.processed_emails_service import ProcessedEmailsService
|
|
from flask.cli import with_appcontext
|
|
import click
|
|
|
|
app = create_app()
|
|
|
|
@app.cli.command()
|
|
@with_appcontext
|
|
def shell():
|
|
"""Run a shell in the app context."""
|
|
import code
|
|
code.interact(local=dict(globals(), **locals()))
|
|
|
|
@app.cli.command("setup-dev")
|
|
def setup_dev():
|
|
"""Set up development environment with Docker Compose."""
|
|
# Create tmp directory for IMAP data if it doesn't exist
|
|
os.makedirs('tmp/imap-data', exist_ok=True)
|
|
|
|
# Start the services
|
|
try:
|
|
subprocess.run(['docker-compose', 'up', '-d'], check=True)
|
|
print("Services started successfully:")
|
|
print("- PostgreSQL: localhost:5432 (database: email_organizer_dev, user: postgres, password: password)")
|
|
print("- IMAP Server: localhost:1143")
|
|
print(" Users:")
|
|
print(" - user1@example.com / password1")
|
|
print(" - user2@example.com / password2")
|
|
print(" Folders: INBOX, Pending, Work, Personal, Receipts, Marketing, Archived")
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error starting services: {e}")
|
|
sys.exit(1)
|
|
except FileNotFoundError:
|
|
print("Docker Compose not found. Please install Docker and Docker Compose.")
|
|
sys.exit(1)
|
|
|
|
def mock_process_emails():
|
|
"""Simulate processing emails with defined rules."""
|
|
with app.app_context():
|
|
# Mock user ID
|
|
mock_user_id = '123e4567-e89b-12d3-a456-426614174000'
|
|
folders = Folder.query.filter_by(user_id=mock_user_id).all()
|
|
|
|
# Mock emails
|
|
emails = [
|
|
{'subject': 'Your Amazon Order', 'from': 'no-reply@amazon.com', 'body': 'Your order has shipped.'},
|
|
{'subject': 'Meeting Reminder', 'from': 'boss@company.com', 'body': 'Don\'t forget the meeting at 3 PM.'},
|
|
{'subject': 'Special Offer!', 'from': 'deals@shop.com', 'body': 'Exclusive discounts inside!'}
|
|
]
|
|
|
|
print("Starting mock email processing...")
|
|
for email in emails:
|
|
print(f"\nProcessing email: {email['subject']}")
|
|
matched = False
|
|
for folder in folders:
|
|
# Simple mock rule matching (in real app, this would be more complex)
|
|
if folder.rule_text.lower() in email['subject'].lower() or folder.rule_text.lower() in email['from'].lower():
|
|
print(f" -> Matched rule '{folder.rule_text}' -> Folder '{folder.name}'")
|
|
matched = True
|
|
break
|
|
if not matched:
|
|
print(" -> No matching rule found.")
|
|
|
|
|
|
@app.cli.command("process-pending-emails")
|
|
@click.option("--user-id", help="Process emails for a specific user ID only")
|
|
@click.option("--folder-name", help="Process emails for a specific folder only")
|
|
@click.option("--batch-size", default=100, help="Number of emails to process in each batch")
|
|
@click.option("--dry-run", is_flag=True, help="Show what would be processed without actually processing")
|
|
@with_appcontext
|
|
def process_pending_emails(user_id, folder_name, batch_size, dry_run):
|
|
"""Process pending emails for all users or specific user/folder."""
|
|
from app.processed_emails_service import ProcessedEmailsService
|
|
|
|
with app.app_context():
|
|
# Build query for users
|
|
user_query = User.query
|
|
if user_id:
|
|
user_query = user_query.filter_by(id=int(user_id))
|
|
|
|
users = user_query.all()
|
|
if not users:
|
|
print("No users found to process")
|
|
return
|
|
|
|
total_processed = 0
|
|
total_users = len(users)
|
|
|
|
print(f"Starting email processing for {total_users} user(s)...")
|
|
|
|
for i, user in enumerate(users, 1):
|
|
print(f"\nProcessing user {i}/{total_users}: {user.email}")
|
|
|
|
# Skip users without IMAP configuration
|
|
if not user.imap_config:
|
|
print(" - Skipping: No IMAP configuration")
|
|
continue
|
|
|
|
try:
|
|
# Initialize services
|
|
imap_service = IMAPService(user)
|
|
processed_emails_service = ProcessedEmailsService(user)
|
|
|
|
# Get folders for this user
|
|
folders = Folder.query.filter_by(user_id=user.id).all()
|
|
|
|
if not folders:
|
|
print(" - No folders found for this user")
|
|
continue
|
|
|
|
# Process each folder
|
|
for folder in folders:
|
|
# Skip if specific folder name is specified and doesn't match
|
|
if folder_name and folder.name != folder_name:
|
|
continue
|
|
|
|
print(f" - Processing folder: {folder.name}")
|
|
|
|
# Get all pending emails for this folder
|
|
pending_emails = ProcessedEmail.query.filter_by(
|
|
user_id=user.id,
|
|
folder_name=folder.name,
|
|
is_processed=False
|
|
).all()
|
|
|
|
if not pending_emails:
|
|
print(f" - No pending emails in this folder")
|
|
continue
|
|
|
|
total_pending = len(pending_emails)
|
|
print(f" - Found {total_pending} pending emails")
|
|
|
|
# Process in batches
|
|
processed_in_folder = 0
|
|
for j in range(0, total_pending, batch_size):
|
|
batch = pending_emails[j:j + batch_size]
|
|
batch_uids = [email.email_uid for email in batch]
|
|
|
|
if dry_run:
|
|
print(f" - Dry run: Would process {len(batch_uids)} emails")
|
|
processed_in_folder += len(batch_uids)
|
|
else:
|
|
# Mark emails as processed
|
|
result = processed_emails_service.mark_emails_processed(
|
|
folder_name=folder.name,
|
|
email_uids=batch_uids
|
|
)
|
|
processed_in_folder += result
|
|
print(f" - Processed {result} emails in this batch")
|
|
|
|
# Commit after each batch to avoid large transactions
|
|
db.session.commit()
|
|
|
|
print(f" - Total processed in folder: {processed_in_folder}/{total_pending}")
|
|
total_processed += processed_in_folder
|
|
|
|
except Exception as e:
|
|
print(f" - Error processing user {user.email}: {str(e)}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
db.session.rollback()
|
|
continue
|
|
|
|
if not dry_run:
|
|
print(f"\nCompleted! Total emails processed: {total_processed}")
|
|
else:
|
|
print(f"\nDry run completed! Total emails would be processed: {total_processed}")
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) > 1 and sys.argv[1] == 'mock-process':
|
|
mock_process_emails()
|
|
else:
|
|
print("Usage: python manage.py mock-process")
|
|
print(" flask setup-dev")
|