141 lines
4.9 KiB
Python
141 lines
4.9 KiB
Python
from typing import List, Optional
|
|
|
|
from database import (
|
|
Message,
|
|
SessionLocal,
|
|
Thread,
|
|
create_db_tables,
|
|
get_thread_messages,
|
|
get_threads_requiring_reply,
|
|
ingest_emails,
|
|
)
|
|
from zoho_client import ZohoClient
|
|
|
|
|
|
def ingest_action(
|
|
account_email: str, days_back: int = 7, max_results: int = 50
|
|
) -> None:
|
|
create_db_tables()
|
|
client = ZohoClient(email=account_email)
|
|
inbox = client.fetch_folder_emails(
|
|
folder="INBOX", max_results=max_results, days_back=days_back
|
|
)
|
|
sent = client.fetch_folder_emails(
|
|
folder="Sent", max_results=max_results, days_back=days_back
|
|
)
|
|
client.close()
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
ingest_emails(
|
|
db, account_email=account_email, emails=inbox, default_folder="INBOX"
|
|
)
|
|
ingest_emails(
|
|
db, account_email=account_email, emails=sent, default_folder="Sent"
|
|
)
|
|
threads: List[Thread] = get_threads_requiring_reply(db, account_email)
|
|
print(f"Threads requiring reply for {account_email}: {len(threads)}")
|
|
for t in threads:
|
|
print(
|
|
f"- Thread #{t.id} | Subject: {t.subject!r} | requires_reply={t.requires_reply}"
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def list_threads_action(
|
|
account_email: Optional[str] = None, limit: int = 20, only_requiring: bool = False
|
|
) -> None:
|
|
create_db_tables()
|
|
db = SessionLocal()
|
|
try:
|
|
q = db.query(Thread).order_by(Thread.updated_at.desc())
|
|
if account_email:
|
|
q = q.filter(Thread.account_email == account_email.lower())
|
|
if only_requiring:
|
|
q = q.filter(Thread.requires_reply.is_(True))
|
|
threads = q.limit(limit).all()
|
|
print(
|
|
f"Showing {len(threads)} threads"
|
|
+ (f" for {account_email}" if account_email else "")
|
|
)
|
|
for t in threads:
|
|
count = db.query(Message).filter(Message.thread_id == t.id).count()
|
|
print(
|
|
f"- id={t.id} msgs={count} requires_reply={t.requires_reply} subject={t.subject!r}"
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def show_thread_action(thread_id: int) -> None:
|
|
create_db_tables()
|
|
db = SessionLocal()
|
|
try:
|
|
thread = db.query(Thread).filter(Thread.id == thread_id).one_or_none()
|
|
if not thread:
|
|
print(f"Thread {thread_id} not found")
|
|
return
|
|
|
|
print(
|
|
f"Thread #{thread.id} subject={thread.subject!r} account={thread.account_email} requires_reply={thread.requires_reply}"
|
|
)
|
|
messages: List[Message] = get_thread_messages(db, thread.id)
|
|
for i, m in enumerate(messages, 1):
|
|
direction = "IN" if m.is_incoming else "OUT"
|
|
snippet = (m.body or "").strip().replace("\n", " ")
|
|
if len(snippet) > 140:
|
|
snippet = snippet[:140] + "..."
|
|
print(
|
|
f"[{i}] {m.date_sent} [{direction}] {m.folder} | from={m.from_email} -> to={m.to_email}\n"
|
|
f" subject={m.subject!r}\n"
|
|
f" message_id={m.message_id} in_reply_to={m.in_reply_to}\n"
|
|
f" body={snippet}"
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
import os
|
|
|
|
parser = argparse.ArgumentParser(description="Email alerts utility")
|
|
sub = parser.add_subparsers(dest="cmd", required=False)
|
|
|
|
p_ingest = sub.add_parser("ingest", help="Fetch INBOX and Sent and ingest into DB")
|
|
p_ingest.add_argument(
|
|
"--account", dest="account", default=os.getenv("ZOHO_EMAIL", "")
|
|
)
|
|
p_ingest.add_argument("--days-back", dest="days_back", type=int, default=7)
|
|
p_ingest.add_argument("--max-results", dest="max_results", type=int, default=50)
|
|
|
|
p_list = sub.add_parser("list-threads", help="List threads")
|
|
p_list.add_argument("--account", dest="account", default=None)
|
|
p_list.add_argument("--limit", dest="limit", type=int, default=20)
|
|
p_list.add_argument("--only-requiring", dest="only_req", action="store_true")
|
|
|
|
p_show = sub.add_parser("show-thread", help="Print all messages in a thread")
|
|
p_show.add_argument("thread_id", type=int)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.cmd == "ingest":
|
|
acct = args.account or os.getenv("ZOHO_EMAIL", "")
|
|
if not acct:
|
|
raise SystemExit("Provide --account or set ZOHO_EMAIL")
|
|
ingest_action(acct, days_back=args.days_back, max_results=args.max_results)
|
|
elif args.cmd == "list-threads":
|
|
list_threads_action(
|
|
account_email=args.account, limit=args.limit, only_requiring=args.only_req
|
|
)
|
|
elif args.cmd == "show-thread":
|
|
show_thread_action(args.thread_id)
|
|
else:
|
|
# Default behavior: run ingest using env and then list requiring-reply threads
|
|
acct = os.getenv("ZOHO_EMAIL", "")
|
|
if not acct:
|
|
parser.print_help()
|
|
raise SystemExit(0)
|
|
ingest_action(acct)
|