scaffolding for processing

This commit is contained in:
2025-08-06 20:16:12 -07:00
parent 8d0d0976b9
commit ab376f5317
2 changed files with 144 additions and 8 deletions

109
manage.py
View File

@@ -2,7 +2,9 @@ import sys
import os
import subprocess
from app import create_app, db
from app.models import Folder, User
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
@@ -65,6 +67,111 @@ def mock_process_emails():
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()